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>
This commit is contained in:
parent
eac96c3efd
commit
337546e83f
@ -1150,7 +1150,7 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
|
||||
struct task_struct *task;
|
||||
struct task_struct *p;
|
||||
unsigned int f_flags;
|
||||
bool reap = true;
|
||||
bool reap = false;
|
||||
struct pid *pid;
|
||||
long ret = 0;
|
||||
|
||||
@ -1177,16 +1177,16 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
|
||||
goto put_task;
|
||||
}
|
||||
|
||||
if (mmget_not_zero(p->mm)) {
|
||||
mm = p->mm;
|
||||
mmgrab(mm);
|
||||
|
||||
/* If the work has been done already, just exit with success */
|
||||
if (test_bit(MMF_OOM_SKIP, &mm->flags))
|
||||
reap = false;
|
||||
else if (!task_will_free_mem(p)) {
|
||||
reap = false;
|
||||
if (task_will_free_mem(p))
|
||||
reap = true;
|
||||
else {
|
||||
/* Error only if the work has not been done already */
|
||||
if (!test_bit(MMF_OOM_SKIP, &mm->flags))
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
task_unlock(p);
|
||||
|
||||
if (!reap)
|
||||
@ -1201,7 +1201,8 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
|
||||
mmap_read_unlock(mm);
|
||||
|
||||
drop_mm:
|
||||
mmdrop(mm);
|
||||
if (mm)
|
||||
mmput(mm);
|
||||
put_task:
|
||||
put_task_struct(task);
|
||||
put_pid:
|
||||
|
Loading…
x
Reference in New Issue
Block a user