UPSTREAM: mm/oom_kill.c: prevent a race between process_mrelease and exit_mmap
Race between process_mrelease and exit_mmap, where free_pgtables is called while __oom_reap_task_mm is in progress, leads to kernel crash during pte_offset_map_lock call. oom-reaper avoids this race by setting MMF_OOM_VICTIM flag and causing exit_mmap to take and release mmap_write_lock, blocking it until oom-reaper releases mmap_read_lock. Reusing MMF_OOM_VICTIM for process_mrelease would be the simplest way to fix this race, however that would be considered a hack. Fix this race by elevating mm->mm_users and preventing exit_mmap from executing until process_mrelease is finished. Patch slightly refactors the code to adapt for a possible mmget_not_zero failure. This fix has considerable negative impact on process_mrelease performance and will likely need later optimization. Link: https://lkml.kernel.org/r/20211022014658.263508-1-surenb@google.com Fixes: 884a7e5964e0 ("mm: introduce process_mrelease system call") Signed-off-by: Suren Baghdasaryan <surenb@google.com> Acked-by: Michal Hocko <mhocko@suse.com> Cc: David Rientjes <rientjes@google.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Roman Gushchin <guro@fb.com> Cc: Rik van Riel <riel@surriel.com> Cc: Minchan Kim <minchan@kernel.org> Cc: Christian Brauner <christian@brauner.io> Cc: Christoph Hellwig <hch@infradead.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: David Hildenbrand <david@redhat.com> Cc: Jann Horn <jannh@google.com> Cc: Shakeel Butt <shakeelb@google.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Christian Brauner <christian.brauner@ubuntu.com> Cc: Florian Weimer <fweimer@redhat.com> Cc: Jan Engelhardt <jengelh@inai.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> (cherry picked from commit 337546e83fc7e50917f44846beee936abb9c9f1f) Bug: 189803002 Signed-off-by: Suren Baghdasaryan <surenb@google.com> Change-Id: I7cf9c869faa7b746995a94ea93f6a617104385aa
This commit is contained in:
@@ -1203,7 +1203,7 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
|
|||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
struct task_struct *p;
|
struct task_struct *p;
|
||||||
unsigned int f_flags;
|
unsigned int f_flags;
|
||||||
bool reap = true;
|
bool reap = false;
|
||||||
struct pid *pid;
|
struct pid *pid;
|
||||||
long ret = 0;
|
long ret = 0;
|
||||||
|
|
||||||
@@ -1230,15 +1230,15 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
|
|||||||
goto put_task;
|
goto put_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
mm = p->mm;
|
if (mmget_not_zero(p->mm)) {
|
||||||
mmgrab(mm);
|
mm = p->mm;
|
||||||
|
if (task_will_free_mem(p))
|
||||||
/* If the work has been done already, just exit with success */
|
reap = true;
|
||||||
if (test_bit(MMF_OOM_SKIP, &mm->flags))
|
else {
|
||||||
reap = false;
|
/* Error only if the work has not been done already */
|
||||||
else if (!task_will_free_mem(p)) {
|
if (!test_bit(MMF_OOM_SKIP, &mm->flags))
|
||||||
reap = false;
|
ret = -EINVAL;
|
||||||
ret = -EINVAL;
|
}
|
||||||
}
|
}
|
||||||
task_unlock(p);
|
task_unlock(p);
|
||||||
|
|
||||||
@@ -1254,7 +1254,8 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
|
|||||||
mmap_read_unlock(mm);
|
mmap_read_unlock(mm);
|
||||||
|
|
||||||
drop_mm:
|
drop_mm:
|
||||||
mmdrop(mm);
|
if (mm)
|
||||||
|
mmput(mm);
|
||||||
put_task:
|
put_task:
|
||||||
put_task_struct(task);
|
put_task_struct(task);
|
||||||
put_pid:
|
put_pid:
|
||||||
|
Reference in New Issue
Block a user