aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugene Teo <eugeneteo@kernel.sg>2008-10-14 15:04:08 +0800
committerWilly Tarreau <w@1wt.eu>2008-11-08 11:11:58 +0100
commit5cb040bdb01e18a59837365ddd65c2e788d01e86 (patch)
tree221be6f06fa8ca4c1b85fde122c7f29d06aec047
parenta61c781740b51d8c59a868bfcd83030eb8f8cc08 (diff)
downloadlinux-2.4-5cb040bdb01e18a59837365ddd65c2e788d01e86.tar.gz
CVE-2008-3275 Linux kernel local filesystem DoS
This is a backport for CVE-2008-3275. "Lookup can install a child dentry for a deleted directory. This keeps the directory dentry alive, and the inode pinned in the cache and on disk, even after all external references have gone away. This isn't a big problem normally, since memory pressure or umount will clear out the directory dentry and its children, releasing the inode. But for UBIFS this causes problems because its orphan area can overflow. Fix this by returning ENOENT for all lookups on a S_DEAD directory before creating a child dentry." Signed-off-by: Eugene Teo <eugeneteo@kernel.sg> [ WT: problem and fix confirmed on ramfs using method described at http://lkml.org/lkml/2008/7/2/83 ] Signed-off-by: Willy Tarreau <w@1wt.eu> (cherry picked from commit f23e4db5d0462de3a3e74686d7e1a4b708bef002)
-rw-r--r--fs/namei.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 374b767b101086..54331623116c19 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -296,7 +296,14 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i
*/
result = d_lookup(parent, name);
if (!result) {
- struct dentry * dentry = d_alloc(parent, name);
+ struct dentry *dentry;
+
+ /* Don't create child dentry for a dead directory. */
+ result = ERR_PTR(-ENOENT);
+ if (IS_DEADDIR(dir))
+ goto out_unlock;
+
+ dentry = d_alloc(parent, name);
result = ERR_PTR(-ENOMEM);
if (dentry) {
lock_kernel();
@@ -307,6 +314,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i
else
result = dentry;
}
+ out_unlock:
up(&dir->i_sem);
return result;
}
@@ -798,7 +806,14 @@ struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
dentry = cached_lookup(base, name, 0);
if (!dentry) {
- struct dentry *new = d_alloc(base, name);
+ struct dentry *new;
+
+ /* Don't create child dentry for a dead directory. */
+ dentry = ERR_PTR(-ENOENT);
+ if (IS_DEADDIR(inode))
+ goto out;
+
+ new = d_alloc(base, name);
dentry = ERR_PTR(-ENOMEM);
if (!new)
goto out;