hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IA53JK
--------------------------------
In freeing process, set memcg->hpool to NULL and then freeing it. To avoid UAF problem of hpool, we have to make sure the users that already hold pointer to hpool don't use the pointer after freeing hpool. The freeing of hpool should block until make sure all such users don't use hpool. Since anyone who want to use hpool have to increase its refcount at first. Use rcu_read_lock() and synchronize_rcu() to guarantee all such users failed to get hpool before freeing hpool.
Fixes: a8a836a36072 ("mm/dynamic_hugetlb: establish the dynamic hugetlb feature framework") Signed-off-by: Liu Shixin liushixin2@huawei.com --- mm/dynamic_hugetlb.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/mm/dynamic_hugetlb.c b/mm/dynamic_hugetlb.c index f6c4c01eae8e..a88b02fef483 100644 --- a/mm/dynamic_hugetlb.c +++ b/mm/dynamic_hugetlb.c @@ -453,6 +453,7 @@ static void put_hpool(struct dhugetlb_pool *hpool) return; if (atomic_dec_and_test(&hpool->refcnt)) { css_put(&hpool->attach_memcg->css); + synchronize_rcu(); kfree(hpool); } } @@ -469,9 +470,11 @@ static struct dhugetlb_pool *get_hpool_from_memcg(struct mem_cgroup *memcg) { struct dhugetlb_pool *hpool;
+ rcu_read_lock(); hpool = memcg->hpool; if (!get_hpool_unless_zero(hpool)) hpool = NULL; + rcu_read_unlock();
return hpool; } @@ -479,15 +482,19 @@ static struct dhugetlb_pool *get_hpool_from_memcg(struct mem_cgroup *memcg) static struct dhugetlb_pool *get_hpool_from_task(struct task_struct *tsk) { struct mem_cgroup *memcg; + struct dhugetlb_pool *hpool;
rcu_read_lock(); memcg = mem_cgroup_from_task(tsk); - rcu_read_unlock(); - - if (!memcg) + if (!memcg || !css_tryget(&memcg->css)) { + rcu_read_unlock(); return NULL; + } + rcu_read_unlock();
- return get_hpool_from_memcg(memcg); + hpool = get_hpool_from_memcg(memcg); + css_put(&memcg->css); + return hpool; }
static int set_hpool_in_dhugetlb_pagelist(unsigned long idx, struct dhugetlb_pool *hpool)