diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-07-28 10:07:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-07-28 10:07:54 -0700 |
commit | 8297b790c65d17544d8298cb81a46f67348c6267 (patch) | |
tree | b92ded22e4a81f8aab315206842fab4d2955c80c /security/inode.c | |
parent | ddf52f12ef500d9f2a5e325e0c86449f594abb25 (diff) | |
parent | f42b8d78dee77107245ec5beee3eb01915bcae7f (diff) |
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/inode.c')
-rw-r--r-- | security/inode.c | 62 |
1 files changed, 19 insertions, 43 deletions
diff --git a/security/inode.c b/security/inode.c index 3913501621fa9..43382ef8896e1 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; |