Commit 337546e8 authored by Suren Baghdasaryan's avatar Suren Baghdasaryan Committed by Linus Torvalds

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: 884a7e59 ("mm: introduce process_mrelease system call")
Signed-off-by: default avatarSuren Baghdasaryan <surenb@google.com>
Acked-by: default avatarMichal 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent eac96c3e
...@@ -1150,7 +1150,7 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags) ...@@ -1150,7 +1150,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;
...@@ -1177,16 +1177,16 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags) ...@@ -1177,16 +1177,16 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
goto put_task; goto put_task;
} }
if (mmget_not_zero(p->mm)) {
mm = p->mm; mm = p->mm;
mmgrab(mm); if (task_will_free_mem(p))
reap = true;
/* If the work has been done already, just exit with success */ else {
if (test_bit(MMF_OOM_SKIP, &mm->flags)) /* Error only if the work has not been done already */
reap = false; if (!test_bit(MMF_OOM_SKIP, &mm->flags))
else if (!task_will_free_mem(p)) {
reap = false;
ret = -EINVAL; ret = -EINVAL;
} }
}
task_unlock(p); task_unlock(p);
if (!reap) if (!reap)
...@@ -1201,7 +1201,8 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags) ...@@ -1201,7 +1201,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:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment