summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-07-28 10:07:54 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-07-28 10:07:54 -0700
commit8297b790c65d17544d8298cb81a46f67348c6267 (patch)
treeb92ded22e4a81f8aab315206842fab4d2955c80c /security
parentMerge tag 'pull-rpc_pipefs' of git://git.kernel.org/pub/scm/linux/kernel/git/... (diff)
parenttpm: don't bother with removal of files in directory we'll be removing (diff)
downloadlinux-8297b790c65d17544d8298cb81a46f67348c6267.tar.gz
linux-8297b790c65d17544d8298cb81a46f67348c6267.zip
Merge tag 'pull-securityfs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull securityfs updates from Al Viro: "Securityfs cleanups and fixes: - one extra reference is enough to pin a dentry down; no need for two. Switch to regular scheme, similar to shmem, debugfs, etc. This fixes a securityfs_recursive_remove() dentry leak, among other things. - we need to have the filesystem pinned to prevent the contents disappearing; what we do not need is pinning it for each file. Doing that only for files and directories in the root is enough. - the previous two changes allow us to get rid of the racy kludges in efi_secret_unlink(), where we can use simple_unlink() instead of securityfs_remove(). Which does not require unlocking and relocking the parent, with all deadlocks that invites. - Make securityfs_remove() take the entire subtree out, turning securityfs_recursive_remove() into its alias. Makes a lot more sense for callers and fixes a mount leak, while we are at it. - Making securityfs_remove() remove the entire subtree allows for much simpler life in most of the users - efi_secret, ima_fs, evm, ipe, tmp get cleaner. I hadn't touched apparmor use of securityfs, but I suspect that it would be useful there as well" * tag 'pull-securityfs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: tpm: don't bother with removal of files in directory we'll be removing ipe: don't bother with removal of files in directory we'll be removing evm_secfs: clear securityfs interactions ima_fs: get rid of lookup-by-dentry stuff ima_fs: don't bother with removal of files in directory we'll be removing efi_secret: clean securityfs use up make securityfs_remove() remove the entire subtree fix locking in efi_secret_unlink() securityfs: pin filesystem only for objects directly in root securityfs: don't pin dentries twice, once is enough...
Diffstat (limited to 'security')
-rw-r--r--security/inode.c62
-rw-r--r--security/integrity/evm/evm_secfs.c15
-rw-r--r--security/integrity/ima/ima_fs.c137
-rw-r--r--security/ipe/fs.c32
-rw-r--r--security/ipe/policy_fs.c4
5 files changed, 73 insertions, 177 deletions
diff --git a/security/inode.c b/security/inode.c
index 3913501621fa..43382ef8896e 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -112,18 +112,20 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode,
struct dentry *dentry;
struct inode *dir, *inode;
int error;
+ bool pinned = false;
if (!(mode & S_IFMT))
mode = (mode & S_IALLUGO) | S_IFREG;
pr_debug("securityfs: creating file '%s'\n",name);
- error = simple_pin_fs(&fs_type, &mount, &mount_count);
- if (error)
- return ERR_PTR(error);
-
- if (!parent)
+ if (!parent) {
+ error = simple_pin_fs(&fs_type, &mount, &mount_count);
+ if (error)
+ return ERR_PTR(error);
+ pinned = true;
parent = mount->mnt_root;
+ }
dir = d_inode(parent);
@@ -159,7 +161,6 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode,
inode->i_fop = fops;
}
d_instantiate(dentry, inode);
- dget(dentry);
inode_unlock(dir);
return dentry;
@@ -168,7 +169,8 @@ out1:
dentry = ERR_PTR(error);
out:
inode_unlock(dir);
- simple_release_fs(&mount, &mount_count);
+ if (pinned)
+ simple_release_fs(&mount, &mount_count);
return dentry;
}
@@ -279,6 +281,12 @@ struct dentry *securityfs_create_symlink(const char *name,
}
EXPORT_SYMBOL_GPL(securityfs_create_symlink);
+static void remove_one(struct dentry *victim)
+{
+ if (victim->d_parent == victim->d_sb->s_root)
+ simple_release_fs(&mount, &mount_count);
+}
+
/**
* securityfs_remove - removes a file or directory from the securityfs filesystem
*
@@ -291,43 +299,11 @@ EXPORT_SYMBOL_GPL(securityfs_create_symlink);
* This function is required to be called in order for the file to be
* removed. No automatic cleanup of files will happen when a module is
* removed; you are responsible here.
- */
-void securityfs_remove(struct dentry *dentry)
-{
- struct inode *dir;
-
- if (IS_ERR_OR_NULL(dentry))
- return;
-
- dir = d_inode(dentry->d_parent);
- inode_lock(dir);
- if (simple_positive(dentry)) {
- if (d_is_dir(dentry))
- simple_rmdir(dir, dentry);
- else
- simple_unlink(dir, dentry);
- dput(dentry);
- }
- inode_unlock(dir);
- simple_release_fs(&mount, &mount_count);
-}
-EXPORT_SYMBOL_GPL(securityfs_remove);
-
-static void remove_one(struct dentry *victim)
-{
- simple_release_fs(&mount, &mount_count);
-}
-
-/**
- * securityfs_recursive_remove - recursively removes a file or directory
- *
- * @dentry: a pointer to a the dentry of the file or directory to be removed.
*
- * This function recursively removes a file or directory in securityfs that was
- * previously created with a call to another securityfs function (like
- * securityfs_create_file() or variants thereof.)
+ * AV: when applied to directory it will take all children out; no need to call
+ * it for descendents if ancestor is getting killed.
*/
-void securityfs_recursive_remove(struct dentry *dentry)
+void securityfs_remove(struct dentry *dentry)
{
if (IS_ERR_OR_NULL(dentry))
return;
@@ -336,7 +312,7 @@ void securityfs_recursive_remove(struct dentry *dentry)
simple_recursive_removal(dentry, remove_one);
simple_release_fs(&mount, &mount_count);
}
-EXPORT_SYMBOL_GPL(securityfs_recursive_remove);
+EXPORT_SYMBOL_GPL(securityfs_remove);
#ifdef CONFIG_SECURITY
static struct dentry *lsm_dentry;
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
index 9b907c2fee60..b0d2aad27850 100644
--- a/security/integrity/evm/evm_secfs.c
+++ b/security/integrity/evm/evm_secfs.c
@@ -17,7 +17,6 @@
#include "evm.h"
static struct dentry *evm_dir;
-static struct dentry *evm_init_tpm;
static struct dentry *evm_symlink;
#ifdef CONFIG_EVM_ADD_XATTRS
@@ -286,7 +285,7 @@ static int evm_init_xattrs(void)
{
evm_xattrs = securityfs_create_file("evm_xattrs", 0660, evm_dir, NULL,
&evm_xattr_ops);
- if (!evm_xattrs || IS_ERR(evm_xattrs))
+ if (IS_ERR(evm_xattrs))
return -EFAULT;
return 0;
@@ -301,21 +300,22 @@ static int evm_init_xattrs(void)
int __init evm_init_secfs(void)
{
int error = 0;
+ struct dentry *dentry;
evm_dir = securityfs_create_dir("evm", integrity_dir);
- if (!evm_dir || IS_ERR(evm_dir))
+ if (IS_ERR(evm_dir))
return -EFAULT;
- evm_init_tpm = securityfs_create_file("evm", 0660,
- evm_dir, NULL, &evm_key_ops);
- if (!evm_init_tpm || IS_ERR(evm_init_tpm)) {
+ dentry = securityfs_create_file("evm", 0660,
+ evm_dir, NULL, &evm_key_ops);
+ if (IS_ERR(dentry)) {
error = -EFAULT;
goto out;
}
evm_symlink = securityfs_create_symlink("evm", NULL,
"integrity/evm/evm", NULL);
- if (!evm_symlink || IS_ERR(evm_symlink)) {
+ if (IS_ERR(evm_symlink)) {
error = -EFAULT;
goto out;
}
@@ -328,7 +328,6 @@ int __init evm_init_secfs(void)
return 0;
out:
securityfs_remove(evm_symlink);
- securityfs_remove(evm_init_tpm);
securityfs_remove(evm_dir);
return error;
}
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index e4a79a9b2d58..87045b09f120 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -116,28 +116,6 @@ void ima_putc(struct seq_file *m, void *data, int datalen)
seq_putc(m, *(char *)data++);
}
-static struct dentry **ascii_securityfs_measurement_lists __ro_after_init;
-static struct dentry **binary_securityfs_measurement_lists __ro_after_init;
-static int securityfs_measurement_list_count __ro_after_init;
-
-static void lookup_template_data_hash_algo(int *algo_idx, enum hash_algo *algo,
- struct seq_file *m,
- struct dentry **lists)
-{
- struct dentry *dentry;
- int i;
-
- dentry = file_dentry(m->file);
-
- for (i = 0; i < securityfs_measurement_list_count; i++) {
- if (dentry == lists[i]) {
- *algo_idx = i;
- *algo = ima_algo_array[i].algo;
- break;
- }
- }
-}
-
/* print format:
* 32bit-le=pcr#
* char[n]=template digest
@@ -160,9 +138,10 @@ int ima_measurements_show(struct seq_file *m, void *v)
algo_idx = ima_sha1_idx;
algo = HASH_ALGO_SHA1;
- if (m->file != NULL)
- lookup_template_data_hash_algo(&algo_idx, &algo, m,
- binary_securityfs_measurement_lists);
+ if (m->file != NULL) {
+ algo_idx = (unsigned long)file_inode(m->file)->i_private;
+ algo = ima_algo_array[algo_idx].algo;
+ }
/* get entry */
e = qe->entry;
@@ -256,9 +235,10 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
algo_idx = ima_sha1_idx;
algo = HASH_ALGO_SHA1;
- if (m->file != NULL)
- lookup_template_data_hash_algo(&algo_idx, &algo, m,
- ascii_securityfs_measurement_lists);
+ if (m->file != NULL) {
+ algo_idx = (unsigned long)file_inode(m->file)->i_private;
+ algo = ima_algo_array[algo_idx].algo;
+ }
/* get entry */
e = qe->entry;
@@ -396,11 +376,6 @@ out:
static struct dentry *ima_dir;
static struct dentry *ima_symlink;
-static struct dentry *binary_runtime_measurements;
-static struct dentry *ascii_runtime_measurements;
-static struct dentry *runtime_measurements_count;
-static struct dentry *violations;
-static struct dentry *ima_policy;
enum ima_fs_flags {
IMA_FS_BUSY,
@@ -417,64 +392,33 @@ static const struct seq_operations ima_policy_seqops = {
};
#endif
-static void __init remove_securityfs_measurement_lists(struct dentry **lists)
-{
- int i;
-
- if (lists) {
- for (i = 0; i < securityfs_measurement_list_count; i++)
- securityfs_remove(lists[i]);
-
- kfree(lists);
- }
-}
-
static int __init create_securityfs_measurement_lists(void)
{
- char file_name[NAME_MAX + 1];
- struct dentry *dentry;
- u16 algo;
- int i;
-
- securityfs_measurement_list_count = NR_BANKS(ima_tpm_chip);
+ int count = NR_BANKS(ima_tpm_chip);
if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip))
- securityfs_measurement_list_count++;
+ count++;
- ascii_securityfs_measurement_lists =
- kcalloc(securityfs_measurement_list_count, sizeof(struct dentry *),
- GFP_KERNEL);
- if (!ascii_securityfs_measurement_lists)
- return -ENOMEM;
-
- binary_securityfs_measurement_lists =
- kcalloc(securityfs_measurement_list_count, sizeof(struct dentry *),
- GFP_KERNEL);
- if (!binary_securityfs_measurement_lists)
- return -ENOMEM;
-
- for (i = 0; i < securityfs_measurement_list_count; i++) {
- algo = ima_algo_array[i].algo;
+ for (int i = 0; i < count; i++) {
+ u16 algo = ima_algo_array[i].algo;
+ char file_name[NAME_MAX + 1];
+ struct dentry *dentry;
sprintf(file_name, "ascii_runtime_measurements_%s",
hash_algo_name[algo]);
dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
- ima_dir, NULL,
+ ima_dir, (void *)(uintptr_t)i,
&ima_ascii_measurements_ops);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
- ascii_securityfs_measurement_lists[i] = dentry;
-
sprintf(file_name, "binary_runtime_measurements_%s",
hash_algo_name[algo]);
dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
- ima_dir, NULL,
+ ima_dir, (void *)(uintptr_t)i,
&ima_measurements_ops);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
-
- binary_securityfs_measurement_lists[i] = dentry;
}
return 0;
@@ -533,8 +477,7 @@ static int ima_release_policy(struct inode *inode, struct file *file)
ima_update_policy();
#if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
- securityfs_remove(ima_policy);
- ima_policy = NULL;
+ securityfs_remove(file->f_path.dentry);
#elif defined(CONFIG_IMA_WRITE_POLICY)
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
#elif defined(CONFIG_IMA_READ_POLICY)
@@ -553,11 +496,9 @@ static const struct file_operations ima_measure_policy_ops = {
int __init ima_fs_init(void)
{
+ struct dentry *dentry;
int ret;
- ascii_securityfs_measurement_lists = NULL;
- binary_securityfs_measurement_lists = NULL;
-
ima_dir = securityfs_create_dir("ima", integrity_dir);
if (IS_ERR(ima_dir))
return PTR_ERR(ima_dir);
@@ -573,57 +514,45 @@ int __init ima_fs_init(void)
if (ret != 0)
goto out;
- binary_runtime_measurements =
- securityfs_create_symlink("binary_runtime_measurements", ima_dir,
+ dentry = securityfs_create_symlink("binary_runtime_measurements", ima_dir,
"binary_runtime_measurements_sha1", NULL);
- if (IS_ERR(binary_runtime_measurements)) {
- ret = PTR_ERR(binary_runtime_measurements);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
goto out;
}
- ascii_runtime_measurements =
- securityfs_create_symlink("ascii_runtime_measurements", ima_dir,
+ dentry = securityfs_create_symlink("ascii_runtime_measurements", ima_dir,
"ascii_runtime_measurements_sha1", NULL);
- if (IS_ERR(ascii_runtime_measurements)) {
- ret = PTR_ERR(ascii_runtime_measurements);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
goto out;
}
- runtime_measurements_count =
- securityfs_create_file("runtime_measurements_count",
+ dentry = securityfs_create_file("runtime_measurements_count",
S_IRUSR | S_IRGRP, ima_dir, NULL,
&ima_measurements_count_ops);
- if (IS_ERR(runtime_measurements_count)) {
- ret = PTR_ERR(runtime_measurements_count);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
goto out;
}
- violations =
- securityfs_create_file("violations", S_IRUSR | S_IRGRP,
+ dentry = securityfs_create_file("violations", S_IRUSR | S_IRGRP,
ima_dir, NULL, &ima_htable_violations_ops);
- if (IS_ERR(violations)) {
- ret = PTR_ERR(violations);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
goto out;
}
- ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
+ dentry = securityfs_create_file("policy", POLICY_FILE_FLAGS,
ima_dir, NULL,
&ima_measure_policy_ops);
- if (IS_ERR(ima_policy)) {
- ret = PTR_ERR(ima_policy);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
goto out;
}
return 0;
out:
- securityfs_remove(ima_policy);
- securityfs_remove(violations);
- securityfs_remove(runtime_measurements_count);
- securityfs_remove(ascii_runtime_measurements);
- securityfs_remove(binary_runtime_measurements);
- remove_securityfs_measurement_lists(ascii_securityfs_measurement_lists);
- remove_securityfs_measurement_lists(binary_securityfs_measurement_lists);
- securityfs_measurement_list_count = 0;
securityfs_remove(ima_symlink);
securityfs_remove(ima_dir);
diff --git a/security/ipe/fs.c b/security/ipe/fs.c
index f40e50bfd2e7..0bb9468b8026 100644
--- a/security/ipe/fs.c
+++ b/security/ipe/fs.c
@@ -12,11 +12,8 @@
#include "policy.h"
#include "audit.h"
-static struct dentry *np __ro_after_init;
static struct dentry *root __ro_after_init;
struct dentry *policy_root __ro_after_init;
-static struct dentry *audit_node __ro_after_init;
-static struct dentry *enforce_node __ro_after_init;
/**
* setaudit() - Write handler for the securityfs node, "ipe/success_audit"
@@ -200,27 +197,26 @@ static int __init ipe_init_securityfs(void)
{
int rc = 0;
struct ipe_policy *ap;
+ struct dentry *dentry;
if (!ipe_enabled)
return -EOPNOTSUPP;
root = securityfs_create_dir("ipe", NULL);
- if (IS_ERR(root)) {
- rc = PTR_ERR(root);
- goto err;
- }
+ if (IS_ERR(root))
+ return PTR_ERR(root);
- audit_node = securityfs_create_file("success_audit", 0600, root,
+ dentry = securityfs_create_file("success_audit", 0600, root,
NULL, &audit_fops);
- if (IS_ERR(audit_node)) {
- rc = PTR_ERR(audit_node);
+ if (IS_ERR(dentry)) {
+ rc = PTR_ERR(dentry);
goto err;
}
- enforce_node = securityfs_create_file("enforce", 0600, root, NULL,
+ dentry = securityfs_create_file("enforce", 0600, root, NULL,
&enforce_fops);
- if (IS_ERR(enforce_node)) {
- rc = PTR_ERR(enforce_node);
+ if (IS_ERR(dentry)) {
+ rc = PTR_ERR(dentry);
goto err;
}
@@ -237,18 +233,14 @@ static int __init ipe_init_securityfs(void)
goto err;
}
- np = securityfs_create_file("new_policy", 0200, root, NULL, &np_fops);
- if (IS_ERR(np)) {
- rc = PTR_ERR(np);
+ dentry = securityfs_create_file("new_policy", 0200, root, NULL, &np_fops);
+ if (IS_ERR(dentry)) {
+ rc = PTR_ERR(dentry);
goto err;
}
return 0;
err:
- securityfs_remove(np);
- securityfs_remove(policy_root);
- securityfs_remove(enforce_node);
- securityfs_remove(audit_node);
securityfs_remove(root);
return rc;
}
diff --git a/security/ipe/policy_fs.c b/security/ipe/policy_fs.c
index db26032ccbe1..9d92d8a14b13 100644
--- a/security/ipe/policy_fs.c
+++ b/security/ipe/policy_fs.c
@@ -438,7 +438,7 @@ static const struct ipefs_file policy_subdir[] = {
*/
void ipe_del_policyfs_node(struct ipe_policy *p)
{
- securityfs_recursive_remove(p->policyfs);
+ securityfs_remove(p->policyfs);
p->policyfs = NULL;
}
@@ -485,6 +485,6 @@ int ipe_new_policyfs_node(struct ipe_policy *p)
return 0;
err:
- securityfs_recursive_remove(policyfs);
+ securityfs_remove(policyfs);
return rc;
}