Commit 9e00cdb0 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds

exec:check_unsafe_exec: kill the dead -EAGAIN and clear_in_exec logic

fs_struct->in_exec == T means that this ->fs is used by a single process
(thread group), and one of the treads does do_execve().

To avoid the mt-exec races this code has the following complications:

	1. check_unsafe_exec() returns -EBUSY if ->in_exec was
	   already set by another thread.

	2. do_execve_common() records "clear_in_exec" to ensure
	   that the error path can only clear ->in_exec if it was
	   set by current.

However, after 9b1bf12d "signals: move cred_guard_mutex from
task_struct to signal_struct" we do not need these complications:

	1. We can't race with our sub-thread, this is called under
	   per-process ->cred_guard_mutex. And we can't race with
	   another CLONE_FS task, we already checked that this fs
	   is not shared.

	   We can remove the  dead -EAGAIN logic.

	2. "out_unmark:" in do_execve_common() is either called
	   under ->cred_guard_mutex, or after de_thread() which
	   kills other threads, so we can't race with sub-thread
	   which could set ->in_exec. And if ->fs is shared with
	   another process ->in_exec should be false anyway.

	   We can clear in_exec unconditionally.

This also means that check_unsafe_exec() can be void.
Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Acked-by: default avatarKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 83f62a2e
...@@ -1223,11 +1223,10 @@ EXPORT_SYMBOL(install_exec_creds); ...@@ -1223,11 +1223,10 @@ EXPORT_SYMBOL(install_exec_creds);
* - the caller must hold ->cred_guard_mutex to protect against * - the caller must hold ->cred_guard_mutex to protect against
* PTRACE_ATTACH * PTRACE_ATTACH
*/ */
static int check_unsafe_exec(struct linux_binprm *bprm) static void check_unsafe_exec(struct linux_binprm *bprm)
{ {
struct task_struct *p = current, *t; struct task_struct *p = current, *t;
unsigned n_fs; unsigned n_fs;
int res = 0;
if (p->ptrace) { if (p->ptrace) {
if (p->ptrace & PT_PTRACE_CAP) if (p->ptrace & PT_PTRACE_CAP)
...@@ -1253,22 +1252,15 @@ static int check_unsafe_exec(struct linux_binprm *bprm) ...@@ -1253,22 +1252,15 @@ static int check_unsafe_exec(struct linux_binprm *bprm)
} }
rcu_read_unlock(); rcu_read_unlock();
if (p->fs->users > n_fs) { if (p->fs->users > n_fs)
bprm->unsafe |= LSM_UNSAFE_SHARE; bprm->unsafe |= LSM_UNSAFE_SHARE;
} else { else
res = -EAGAIN; p->fs->in_exec = 1;
if (!p->fs->in_exec) {
p->fs->in_exec = 1;
res = 1;
}
}
spin_unlock(&p->fs->lock); spin_unlock(&p->fs->lock);
return res;
} }
/* /*
* Fill the binprm structure from the inode. * Fill the binprm structure from the inode.
* Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
* *
* This may be called multiple times for binary chains (scripts for example). * This may be called multiple times for binary chains (scripts for example).
...@@ -1453,7 +1445,6 @@ static int do_execve_common(const char *filename, ...@@ -1453,7 +1445,6 @@ static int do_execve_common(const char *filename,
struct linux_binprm *bprm; struct linux_binprm *bprm;
struct file *file; struct file *file;
struct files_struct *displaced; struct files_struct *displaced;
bool clear_in_exec;
int retval; int retval;
/* /*
...@@ -1485,10 +1476,7 @@ static int do_execve_common(const char *filename, ...@@ -1485,10 +1476,7 @@ static int do_execve_common(const char *filename,
if (retval) if (retval)
goto out_free; goto out_free;
retval = check_unsafe_exec(bprm); check_unsafe_exec(bprm);
if (retval < 0)
goto out_free;
clear_in_exec = retval;
current->in_execve = 1; current->in_execve = 1;
file = open_exec(filename); file = open_exec(filename);
...@@ -1558,8 +1546,7 @@ static int do_execve_common(const char *filename, ...@@ -1558,8 +1546,7 @@ static int do_execve_common(const char *filename,
} }
out_unmark: out_unmark:
if (clear_in_exec) current->fs->in_exec = 0;
current->fs->in_exec = 0;
current->in_execve = 0; current->in_execve = 0;
out_free: out_free:
......
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