From: Guo Mengqi guomengqi3@huawei.com
ascend inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ODMN CVE: NA
------------------------------------------------- Fix following situation:
when the last process in a group exits, and a second process tries to add to this group.
The second process may get a invalid spg. However the group's use_count is increased by 1, which caused the first process failed to free the group when it exits. And then second process called sp_group_drop --> free_sp_group and cause a double request of rwsem.
Signed-off-by: Guo Mengqi guomengqi3@huawei.com Reviewed-by: Weilong Chen chenweilong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- mm/share_pool.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/mm/share_pool.c b/mm/share_pool.c index 428742f5d4044..c79ea4bb06026 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -711,20 +711,25 @@ static void free_new_spg_id(bool new, int spg_id) free_sp_group_id(spg_id); }
-static void free_sp_group(struct sp_group *spg) +static void free_sp_group_locked(struct sp_group *spg) { fput(spg->file); fput(spg->file_hugetlb); free_spg_stat(spg->id); - down_write(&sp_group_sem); idr_remove(&sp_group_idr, spg->id); - up_write(&sp_group_sem); free_sp_group_id((unsigned int)spg->id); kfree(spg); system_group_count--; WARN(system_group_count < 0, "unexpected group count\n"); }
+static void free_sp_group(struct sp_group *spg) +{ + down_write(&sp_group_sem); + free_sp_group_locked(spg); + up_write(&sp_group_sem); +} + static void sp_group_drop(struct sp_group *spg) { if (atomic_dec_and_test(&spg->use_count)) @@ -4460,14 +4465,15 @@ void sp_group_post_exit(struct mm_struct *mm) sp_proc_stat_drop(stat); }
- /* lockless traverse */ + down_write(&sp_group_sem); list_for_each_entry_safe(spg_node, tmp, &master->node_list, group_node) { spg = spg_node->spg; /* match with refcount inc in sp_group_add_task */ - sp_group_drop(spg); + if (atomic_dec_and_test(&spg->use_count)) + free_sp_group_locked(spg); kfree(spg_node); } - + up_write(&sp_group_sem); kfree(master); }
From: Guo Mengqi guomengqi3@huawei.com
ascend inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ODJ6 CVE: NA
---------------------------
Remove the unnecessary current->mm NULL check in sp_unshare_uva, and allow process to unshare kernel mapped addresses in do_exit().
Signed-off-by: Guo Mengqi guomengqi3@huawei.com Reviewed-by: Weilong Chen chenweilong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- mm/share_pool.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/mm/share_pool.c b/mm/share_pool.c index c79ea4bb06026..0ba516e16ef29 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -3283,16 +3283,11 @@ EXPORT_SYMBOL_GPL(mg_sp_make_share_u2k); * * Procedure of unshare uva must be compatible with: * - * 1. DVPP channel destroy procedure: - * do_exit() -> exit_mm() (mm no longer in spg and current->mm == NULL) -> - * exit_task_work() -> task_work_run() -> __fput() -> ... -> vdec_close() -> - * sp_unshare(uva, SPG_ID_DEFAULT) - * - * 2. Process A once was the target of k2u(to group), then it exits. + * 1. Process A once was the target of k2u(to group), then it exits. * Guard worker kthread tries to free this uva and it must succeed, otherwise * spa of this uva leaks. * - * This also means we must trust DVPP channel destroy and guard worker code. + * This also means we must trust guard worker code. */ static int sp_unshare_uva(unsigned long uva, unsigned long size) { @@ -3339,7 +3334,11 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size) }
if (spa->type == SPA_TYPE_K2TASK) { - if (!current->mm || spa->applier != current->tgid) { + /* + * Only allow the original k2task applier process to unshare this uva. + * Kthreads or other processes are not allowed to unshare the uva. + */ + if (spa->applier != current->tgid) { pr_err_ratelimited("unshare uva(to task) no permission\n"); ret = -EPERM; goto out_drop_area;