提交 ef680bf9 编写于 作者: W Wang Wensheng 提交者: Zhong Jinghua

mm/sharepool: Fix double delete list in sp_group_exit

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I650K6

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

There is a double delete list problem in sp_group_exit
Unable to handle kernel paging request at virtual address
dead000000000108
Call trace:
 sp_group_exit+0x104/0x238
  do_exit+0x188/0xb88
  __arm64_sys_exit+0x24/0x28

Calls to sp_group_exit depends on the value of group_dead, which is
controlled by CLONE_THREAD. If process A clone B with CLONE_VM and
*NO* CLONE_THREAD. A and B will have group_dead = 1 and have the same
mm_struct on exit. So sp_group_exit processes an mm_struct more than
once.

To sovle the problem, we check the tgid in sp_group_exit and allow only
the parent process to continue.

Similar check should be added in mg_sp_group_add/del_task.
Signed-off-by: NWang Wensheng <wangwensheng4@huawei.com>
上级 e6c41f13
......@@ -224,6 +224,7 @@ struct sp_group {
/* a per-process(per mm) struct which manages a sp_group_node list */
struct sp_group_master {
pid_t tgid;
/*
* number of sp groups the process belongs to,
* a.k.a the number of sp_node in node_list
......@@ -584,6 +585,7 @@ static int sp_init_group_master_locked(struct task_struct *tsk, struct mm_struct
INIT_LIST_HEAD(&master->node_list);
master->count = 0;
master->mm = mm;
master->tgid = tsk->tgid;
sp_init_group_master_stat(tsk->tgid, mm, &master->instat);
mm->sp_group_master = master;
sp_add_group_master(master);
......@@ -1465,6 +1467,15 @@ int mg_sp_group_add_task(int tgid, unsigned long prot, int spg_id)
goto out_put_task;
}
if (mm->sp_group_master && mm->sp_group_master->tgid != tgid) {
up_write(&sp_group_sem);
pr_err("add: task(%d) is a vfork child of the original task(%d)\n",
tgid, mm->sp_group_master->tgid);
ret = -EINVAL;
free_new_spg_id(id_newly_generated, spg_id);
goto out_put_mm;
}
spg = find_or_alloc_sp_group(spg_id, flag);
if (IS_ERR(spg)) {
up_write(&sp_group_sem);
......@@ -1669,6 +1680,14 @@ int mg_sp_group_del_task(int tgid, int spg_id)
goto out_put_mm;
}
if (mm->sp_group_master->tgid != tgid) {
up_write(&sp_group_sem);
pr_err("del: task(%d) is a vfork child of the original task(%d)\n",
tgid, mm->sp_group_master->tgid);
ret = -EINVAL;
goto out_put_mm;
}
spg_node = find_spg_node_by_spg(mm, spg);
if (!spg_node) {
up_write(&sp_group_sem);
......@@ -4200,6 +4219,11 @@ int sp_group_exit(void)
return 0;
}
if (master->tgid != current->tgid) {
up_write(&sp_group_sem);
return 0;
}
list_for_each_entry_safe(spg_node, tmp, &master->node_list, group_node) {
spg = spg_node->spg;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册