diff options
author | Oleg Nesterov <oleg@redhat.com> | 2014-01-23 18:55:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-23 19:37:02 -0500 |
commit | 9e00cdb091b008cb3c78192651180896de412a63 (patch) | |
tree | 58b9c75f95f3fbd91d66f16f00879652b1bb1fc4 /fs/exec.c | |
parent | 83f62a2eacb1d6945c78523f20e0c34b5d94913c (diff) |
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 9b1bf12d5d51 "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>
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 29 |
1 files changed, 8 insertions, 21 deletions
@@ -1223,11 +1223,10 @@ EXPORT_SYMBOL(install_exec_creds); | |||
1223 | * - the caller must hold ->cred_guard_mutex to protect against | 1223 | * - the caller must hold ->cred_guard_mutex to protect against |
1224 | * PTRACE_ATTACH | 1224 | * PTRACE_ATTACH |
1225 | */ | 1225 | */ |
1226 | static int check_unsafe_exec(struct linux_binprm *bprm) | 1226 | static void check_unsafe_exec(struct linux_binprm *bprm) |
1227 | { | 1227 | { |
1228 | struct task_struct *p = current, *t; | 1228 | struct task_struct *p = current, *t; |
1229 | unsigned n_fs; | 1229 | unsigned n_fs; |
1230 | int res = 0; | ||
1231 | 1230 | ||
1232 | if (p->ptrace) { | 1231 | if (p->ptrace) { |
1233 | if (p->ptrace & PT_PTRACE_CAP) | 1232 | if (p->ptrace & PT_PTRACE_CAP) |
@@ -1253,22 +1252,15 @@ static int check_unsafe_exec(struct linux_binprm *bprm) | |||
1253 | } | 1252 | } |
1254 | rcu_read_unlock(); | 1253 | rcu_read_unlock(); |
1255 | 1254 | ||
1256 | if (p->fs->users > n_fs) { | 1255 | if (p->fs->users > n_fs) |
1257 | bprm->unsafe |= LSM_UNSAFE_SHARE; | 1256 | bprm->unsafe |= LSM_UNSAFE_SHARE; |
1258 | } else { | 1257 | else |
1259 | res = -EAGAIN; | 1258 | p->fs->in_exec = 1; |
1260 | if (!p->fs->in_exec) { | ||
1261 | p->fs->in_exec = 1; | ||
1262 | res = 1; | ||
1263 | } | ||
1264 | } | ||
1265 | spin_unlock(&p->fs->lock); | 1259 | spin_unlock(&p->fs->lock); |
1266 | |||
1267 | return res; | ||
1268 | } | 1260 | } |
1269 | 1261 | ||
1270 | /* | 1262 | /* |
1271 | * Fill the binprm structure from the inode. | 1263 | * Fill the binprm structure from the inode. |
1272 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes | 1264 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes |
1273 | * | 1265 | * |
1274 | * This may be called multiple times for binary chains (scripts for example). | 1266 | * 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 | struct linux_binprm *bprm; | 1445 | struct linux_binprm *bprm; |
1454 | struct file *file; | 1446 | struct file *file; |
1455 | struct files_struct *displaced; | 1447 | struct files_struct *displaced; |
1456 | bool clear_in_exec; | ||
1457 | int retval; | 1448 | int retval; |
1458 | 1449 | ||
1459 | /* | 1450 | /* |
@@ -1485,10 +1476,7 @@ static int do_execve_common(const char *filename, | |||
1485 | if (retval) | 1476 | if (retval) |
1486 | goto out_free; | 1477 | goto out_free; |
1487 | 1478 | ||
1488 | retval = check_unsafe_exec(bprm); | 1479 | check_unsafe_exec(bprm); |
1489 | if (retval < 0) | ||
1490 | goto out_free; | ||
1491 | clear_in_exec = retval; | ||
1492 | current->in_execve = 1; | 1480 | current->in_execve = 1; |
1493 | 1481 | ||
1494 | file = open_exec(filename); | 1482 | file = open_exec(filename); |
@@ -1558,8 +1546,7 @@ out_file: | |||
1558 | } | 1546 | } |
1559 | 1547 | ||
1560 | out_unmark: | 1548 | out_unmark: |
1561 | if (clear_in_exec) | 1549 | current->fs->in_exec = 0; |
1562 | current->fs->in_exec = 0; | ||
1563 | current->in_execve = 0; | 1550 | current->in_execve = 0; |
1564 | 1551 | ||
1565 | out_free: | 1552 | out_free: |