提交 6a8c6793 编写于 作者: Y yangerkun 提交者: Zheng Zengkai

fs/dcache.c: avoid panic while lockref of dentry overflow

hulk inclusion
category: bugfix
bugzilla: 185799, https://gitee.com/openeuler/kernel/issues/I4JWYM
CVE: NA

---------------------------

We use lockref for dentry reference without notice that so many negative
dentry under one dir can lead to overflow of lockref. This can lead to
system crash if we do this under root dir.

Since there is not a perfect solution, we just limit max number of
dentry count up to INT_MAX / 2. Also, it will cost a lot of time from
INT_MAX / 2 to INT_MAX, so we no need to do this under protection of
dentry lock.

Also, we limit the FILES_MAX to INT_MAX / 2, since a lot open for
same file can lead to overflow too.

Changelog:
v1->v2: add a function to do check / add a Macro to mean INT_MAX / 2
Signed-off-by: Nyangerkun <yangerkun@huawei.com>
Reviewed-by: NMiao Xie <miaoxie@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>

Conflicts:
	fs/dcache.c
Reviewed-by: NZhang Yi <yi.zhang@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 0e797399
...@@ -1774,6 +1774,18 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) ...@@ -1774,6 +1774,18 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
return dentry; return dentry;
} }
static inline bool d_forbid_overflow(struct dentry *dentry)
{
if (unlikely(d_count(dentry) >= D_COUNT_MAX)) {
shrink_dcache_parent(dentry);
if (d_count(dentry) >= D_COUNT_MAX)
return false;
}
return true;
}
/** /**
* d_alloc - allocate a dcache entry * d_alloc - allocate a dcache entry
* @parent: parent of entry to allocate * @parent: parent of entry to allocate
...@@ -1785,9 +1797,15 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) ...@@ -1785,9 +1797,15 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
*/ */
struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
{ {
struct dentry *dentry = __d_alloc(parent->d_sb, name); struct dentry *dentry = NULL;
if (unlikely(!d_forbid_overflow(parent)))
goto out;
dentry = __d_alloc(parent->d_sb, name);
if (!dentry) if (!dentry)
return NULL; goto out;
spin_lock(&parent->d_lock); spin_lock(&parent->d_lock);
/* /*
* don't need child lock because it is not subject * don't need child lock because it is not subject
...@@ -1797,7 +1815,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) ...@@ -1797,7 +1815,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
dentry->d_parent = parent; dentry->d_parent = parent;
list_add(&dentry->d_child, &parent->d_subdirs); list_add(&dentry->d_child, &parent->d_subdirs);
spin_unlock(&parent->d_lock); spin_unlock(&parent->d_lock);
out:
return dentry; return dentry;
} }
EXPORT_SYMBOL(d_alloc); EXPORT_SYMBOL(d_alloc);
...@@ -1810,11 +1828,17 @@ EXPORT_SYMBOL(d_alloc_anon); ...@@ -1810,11 +1828,17 @@ EXPORT_SYMBOL(d_alloc_anon);
struct dentry *d_alloc_cursor(struct dentry * parent) struct dentry *d_alloc_cursor(struct dentry * parent)
{ {
struct dentry *dentry = d_alloc_anon(parent->d_sb); struct dentry *dentry = NULL;
if (unlikely(!d_forbid_overflow(parent)))
goto out;
dentry = d_alloc_anon(parent->d_sb);
if (dentry) { if (dentry) {
dentry->d_flags |= DCACHE_DENTRY_CURSOR; dentry->d_flags |= DCACHE_DENTRY_CURSOR;
dentry->d_parent = dget(parent); dentry->d_parent = dget(parent);
} }
out:
return dentry; return dentry;
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/module.h> #include <linux/module.h>
#define FILES_MAX ULONG_MAX #define FILES_MAX D_COUNT_MAX
#define FILES_MAX_STR "max" #define FILES_MAX_STR "max"
static bool no_acct; static bool no_acct;
......
...@@ -44,6 +44,9 @@ ...@@ -44,6 +44,9 @@
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <uapi/linux/fs.h> #include <uapi/linux/fs.h>
#define D_COUNT_MAX (INT_MAX / 2)
struct backing_dev_info; struct backing_dev_info;
struct bdi_writeback; struct bdi_writeback;
struct bio; struct bio;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册