[PATCH AUTOSEL 5.4 9/9] securityfs: don't pin dentries twice, once is enough...
Sasha Levin
sashal at kernel.org
Sun Aug 3 21:23:09 UTC 2025
From: Al Viro <viro at zeniv.linux.org.uk>
[ Upstream commit 27cd1bf1240d482e4f02ca4f9812e748f3106e4f ]
incidentally, securityfs_recursive_remove() is broken without that -
it leaks dentries, since simple_recursive_removal() does not expect
anything of that sort. It could be worked around by dput() in
remove_one() callback, but it's easier to just drop that double-get
stuff.
Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
LLM Generated explanations, may be completely bogus:
Now I have a clear understanding of the issue. Let me analyze this:
**YES**
This commit should be backported to stable kernel trees. Here's the
extensive analysis:
## Analysis of the Double Dentry Reference Issue
The commit fixes a clear bug in securityfs where dentries are being
pinned twice:
1. **The Bug**: In `securityfs_create_dentry()` at line 162, there's a
`dget(dentry)` call immediately after `d_instantiate(dentry, inode)`.
This creates an extra reference count on the dentry that is never
properly balanced.
2. **Impact on `securityfs_remove()`**: The traditional
`securityfs_remove()` function does call `dput(dentry)` at line 309,
which would balance the extra `dget()`. However, this only happens
for the simple remove case.
3. **Critical Impact on `securityfs_recursive_remove()`**: The newly
added `securityfs_recursive_remove()` function (added in commit
7138679ff2a2) uses `simple_recursive_removal()` which expects normal
dentry reference counting. The `simple_recursive_removal()` function
in fs/libfs.c:
- Takes its own reference with `dget(dentry)` at the beginning
- Properly releases references with `dput()` calls throughout its
execution
- Does NOT expect the dentries to have extra references
4. **The Leak**: When `securityfs_recursive_remove()` is called, the
extra reference from the `dget()` in `securityfs_create_dentry()` is
never released because:
- `simple_recursive_removal()` only releases the references it takes
- The `remove_one()` callback only calls `simple_release_fs()` but
doesn't do any `dput()`
- This results in dentries being leaked with a refcount that never
reaches zero
5. **Pattern Consistency**: Looking at similar filesystem
implementations like debugfs (fs/debugfs/inode.c), they do NOT add an
extra `dget()` after `d_instantiate()`. The pattern is simply:
```c
d_instantiate(dentry, inode);
return end_creating(dentry);
```
No extra reference is taken.
6. **Backport Criteria Met**:
- **Fixes a real bug**: Memory leak of dentries when using
`securityfs_recursive_remove()`
- **Small and contained**: Single-line removal in two locations
- **No side effects**: Removing the extra `dget()` brings the code in
line with standard VFS patterns
- **Low regression risk**: The fix makes securityfs consistent with
other similar filesystems
- **Important for stability**: Memory leaks in kernel filesystem code
can accumulate over time
The commit message clearly identifies this as a bug fix
("securityfs_recursive_remove() is broken without that - it leaks
dentries"), and the fix is minimal and correct. This makes it an ideal
candidate for stable backporting.
security/inode.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/security/inode.c b/security/inode.c
index 6c326939750d..e6e07787eec9 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -159,7 +159,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;
@@ -306,7 +305,6 @@ void securityfs_remove(struct dentry *dentry)
simple_rmdir(dir, dentry);
else
simple_unlink(dir, dentry);
- dput(dentry);
}
inode_unlock(dir);
simple_release_fs(&mount, &mount_count);
--
2.39.5
More information about the Linux-security-module-archive
mailing list