mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
fork: take mmap_lock before copying mm_struct
dup_mm() copies the parent's mm_struct before dup_mmap() takes the
mmap_lock. A concurrent brk() can leave the child with a stale mm->brk
and newer heap mappings, causing later brk() requests to fail.
Other operations (e.g., PR_SET_MM) on the parent's mm_struct can similarly
cause inconsistencies.
As a simple and robust fix, grab the parent's mmap_lock earlier. This
way we don't need to update individual mm fields in dup_mmap() and
keep missing ones. Stop updating the 4 existing members (total_vm, data_vm,
exec_vm, stack_vm), as that is now no longer required.
Keep releasing the parent's mmap_lock in dup_mmap(), before
userfaultfd completion, to avoid moving the userfaultfd handling into the
caller. This should get cleaned up later.
Move uprobe_start_dup_mmap() to preserve the lock ordering.
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Rik van Riel <riel@surriel.com>
Reviewed-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Harry Yoo (Meta) <harry@kernel.org>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: SJ Park <sj@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Link: https://patch.msgid.link/20261031-fixes_core-v3-2-d6437171ecc3@kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
This commit is contained in:
parent
65a9bf08a3
commit
ef694e2d21
|
|
@ -1533,12 +1533,19 @@ static struct mm_struct *dup_mm(struct task_struct *tsk,
|
|||
if (!mm)
|
||||
goto fail_nomem;
|
||||
|
||||
uprobe_start_dup_mmap();
|
||||
if (mmap_write_lock_killable(oldmm)) {
|
||||
free_mm(mm);
|
||||
goto fail_uprobe;
|
||||
}
|
||||
|
||||
memcpy(mm, oldmm, sizeof(*mm));
|
||||
|
||||
if (!mm_init(mm, tsk))
|
||||
goto fail_nomem;
|
||||
if (!mm_init(mm, tsk)) {
|
||||
mmap_write_unlock(oldmm);
|
||||
goto fail_uprobe;
|
||||
}
|
||||
|
||||
uprobe_start_dup_mmap();
|
||||
err = dup_mmap(mm, oldmm);
|
||||
if (err)
|
||||
goto free_pt;
|
||||
|
|
@ -1557,9 +1564,10 @@ static struct mm_struct *dup_mm(struct task_struct *tsk,
|
|||
mm->binfmt = NULL;
|
||||
mm_init_owner(mm, NULL);
|
||||
mmput(mm);
|
||||
if (err)
|
||||
uprobe_end_dup_mmap();
|
||||
|
||||
if (!err)
|
||||
return NULL;
|
||||
fail_uprobe:
|
||||
uprobe_end_dup_mmap();
|
||||
fail_nomem:
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1713,8 +1713,7 @@ __latent_entropy int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
|
|||
LIST_HEAD(uf);
|
||||
VMA_ITERATOR(vmi, mm, 0);
|
||||
|
||||
if (mmap_write_lock_killable(oldmm))
|
||||
return -EINTR;
|
||||
mmap_assert_write_locked(oldmm);
|
||||
flush_cache_dup_mm(oldmm);
|
||||
uprobe_dup_mmap(oldmm, mm);
|
||||
/*
|
||||
|
|
@ -1725,11 +1724,6 @@ __latent_entropy int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
|
|||
/* No ordering required: file already has been exposed. */
|
||||
dup_mm_exe_file(mm, oldmm);
|
||||
|
||||
mm->total_vm = oldmm->total_vm;
|
||||
mm->data_vm = oldmm->data_vm;
|
||||
mm->exec_vm = oldmm->exec_vm;
|
||||
mm->stack_vm = oldmm->stack_vm;
|
||||
|
||||
/* Use __mt_dup() to efficiently build an identical maple tree. */
|
||||
retval = __mt_dup(&oldmm->mm_mt, &mm->mm_mt, GFP_KERNEL);
|
||||
if (unlikely(retval))
|
||||
|
|
|
|||
|
|
@ -1887,7 +1887,7 @@ subsys_initcall(init_admin_reserve);
|
|||
|
||||
int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
|
||||
{
|
||||
mmap_write_lock(oldmm);
|
||||
mmap_assert_write_locked(oldmm);
|
||||
dup_mm_exe_file(mm, oldmm);
|
||||
mmap_write_unlock(oldmm);
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user