Skip to content

Commit 08dcc40

Browse files
howlettopsiff
authored andcommitted
kernel: be more careful about dup_mmap() failures and uprobe registering
mainline inclusion from mainline-v6.14-rc1 category: bugfix If a memory allocation fails during dup_mmap(), the maple tree can be left in an unsafe state for other iterators besides the exit path. All the locks are dropped before the exit_mmap() call (in mm/mmap.c), but the incomplete mm_struct can be reached through (at least) the rmap finding the vmas which have a pointer back to the mm_struct. Up to this point, there have been no issues with being able to find an mm_struct that was only partially initialised. Syzbot was able to make the incomplete mm_struct fail with recent forking changes, so it has been proven unsafe to use the mm_struct that hasn't been initialised, as referenced in the link below. Although 8ac662f ("fork: avoid inappropriate uprobe access to invalid mm") fixed the uprobe access, it does not completely remove the race. This patch sets the MMF_OOM_SKIP to avoid the iteration of the vmas on the oom side (even though this is extremely unlikely to be selected as an oom victim in the race window), and sets MMF_UNSTABLE to avoid other potential users from using a partially initialised mm_struct. When registering vmas for uprobe, skip the vmas in an mm that is marked unstable. Modifying a vma in an unstable mm may cause issues if the mm isn't fully initialised. Link: https://lore.kernel.org/all/6756d273.050a0220.2477f.003d.GAE@google.com/ Link: https://lkml.kernel.org/r/20250127170221.1761366-1-Liam.Howlett@oracle.com Fixes: d240629 ("fork: use __mt_dup() to duplicate maple tree in dup_mmap()") Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com> Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Jann Horn <jannh@google.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Peng Zhang <zhangpeng.00@bytedance.com> Cc: Matthew Wilcox <willy@infradead.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> (cherry picked from commit 64c37e1) Signed-off-by: Wentao Guan <guanwentao@uniontech.com> Conflicts: kernel/events/uprobes.c
1 parent 9d6a9f8 commit 08dcc40

File tree

2 files changed

+21
-3
lines changed

2 files changed

+21
-3
lines changed

kernel/events/uprobes.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
#include <linux/task_work.h>
2727
#include <linux/shmem_fs.h>
2828
#include <linux/khugepaged.h>
29+
#include <linux/rcupdate_trace.h>
30+
#include <linux/workqueue.h>
31+
#include <linux/srcu.h>
32+
#include <linux/oom.h> /* check_stable_address_space */
2933

3034
#include <linux/uprobes.h>
3135

@@ -1053,6 +1057,9 @@ register_for_each_vma(struct uprobe *uprobe, struct uprobe_consumer *new)
10531057
goto free;
10541058

10551059
mmap_write_lock(mm);
1060+
if (check_stable_address_space(mm))
1061+
goto unlock;
1062+
10561063
vma = find_vma(mm, info->vaddr);
10571064
if (!vma || !valid_vma(vma, is_register) ||
10581065
file_inode(vma->vm_file) != uprobe->inode)

kernel/fork.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -773,16 +773,27 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
773773
mt_set_in_rcu(vmi.mas.tree);
774774
ksm_fork(mm, oldmm);
775775
khugepaged_fork(mm, oldmm);
776-
} else if (mpnt) {
776+
} else {
777+
777778
/*
778779
* The entire maple tree has already been duplicated. If the
779780
* mmap duplication fails, mark the failure point with
780781
* XA_ZERO_ENTRY. In exit_mmap(), if this marker is encountered,
781782
* stop releasing VMAs that have not been duplicated after this
782783
* point.
783784
*/
784-
mas_set_range(&vmi.mas, mpnt->vm_start, mpnt->vm_end - 1);
785-
mas_store(&vmi.mas, XA_ZERO_ENTRY);
785+
if (mpnt) {
786+
mas_set_range(&vmi.mas, mpnt->vm_start, mpnt->vm_end - 1);
787+
mas_store(&vmi.mas, XA_ZERO_ENTRY);
788+
/* Avoid OOM iterating a broken tree */
789+
set_bit(MMF_OOM_SKIP, &mm->flags);
790+
}
791+
/*
792+
* The mm_struct is going to exit, but the locks will be dropped
793+
* first. Set the mm_struct as unstable is advisable as it is
794+
* not fully initialised.
795+
*/
796+
set_bit(MMF_UNSTABLE, &mm->flags);
786797
}
787798
out:
788799
mmap_write_unlock(mm);

0 commit comments

Comments
 (0)