kernel/fork: factor out replacing the current MM exe_file

Let's factor the main logic out into replace_mm_exe_file(), such that
all mm->exe_file logic is contained in kernel/fork.c.

While at it, perform some simple cleanups that are possible now that
we're simplifying the individual functions.

Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: Christian König <christian.koenig@amd.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
This commit is contained in:
David Hildenbrand 2021-04-23 10:20:25 +02:00
parent 42be8b4253
commit 35d7bdc860
3 changed files with 43 additions and 35 deletions

View file

@ -1148,9 +1148,7 @@ void mmput_async(struct mm_struct *mm)
*
* Main users are mmput() and sys_execve(). Callers prevent concurrent
* invocations: in mmput() nobody alive left, in execve task is single
* threaded. sys_prctl(PR_SET_MM_MAP/EXE_FILE) also needs to set the
* mm->exe_file, but does so without using set_mm_exe_file() in order
* to avoid the need for any locks.
* threaded.
*/
void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
{
@ -1170,6 +1168,46 @@ void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
fput(old_exe_file);
}
/**
* replace_mm_exe_file - replace a reference to the mm's executable file
*
* This changes mm's executable file (shown as symlink /proc/[pid]/exe),
* dealing with concurrent invocation and without grabbing the mmap lock in
* write mode.
*
* Main user is sys_prctl(PR_SET_MM_MAP/EXE_FILE).
*/
int replace_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
{
struct vm_area_struct *vma;
struct file *old_exe_file;
int ret = 0;
/* Forbid mm->exe_file change if old file still mapped. */
old_exe_file = get_mm_exe_file(mm);
if (old_exe_file) {
mmap_read_lock(mm);
for (vma = mm->mmap; vma && !ret; vma = vma->vm_next) {
if (!vma->vm_file)
continue;
if (path_equal(&vma->vm_file->f_path,
&old_exe_file->f_path))
ret = -EBUSY;
}
mmap_read_unlock(mm);
fput(old_exe_file);
if (ret)
return ret;
}
/* set the new file, lockless */
get_file(new_exe_file);
old_exe_file = xchg(&mm->exe_file, new_exe_file);
if (old_exe_file)
fput(old_exe_file);
return 0;
}
/**
* get_mm_exe_file - acquire a reference to the mm's executable file
*