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 9b1bf12d5d
"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: Oleg Nesterov <oleg@redhat.com>
Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
83f62a2eac
commit
9e00cdb091
29
fs/exec.c
29
fs/exec.c
|
@ -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)
|
||||||
}
|
}
|
||||||
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,
|
||||||
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,
|
||||||
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 @@ out_file:
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
||||||
|
|
Loading…
Reference in a new issue