summaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-05-05 02:11:36 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2014-10-09 08:39:00 +0200
commit19d860a140beac48a1377f179e693abe86a9dac9 (patch)
tree4da809a162a3b9aea8575828f52e150b26ca6ff1 /fs/exec.c
parentdcache.c: call ->d_prune() regardless of d_unhashed() (diff)
downloadlinux-19d860a140beac48a1377f179e693abe86a9dac9.tar.xz
linux-19d860a140beac48a1377f179e693abe86a9dac9.zip
handle suicide on late failure exits in execve() in search_binary_handler()
... rather than doing that in the guts of ->load_binary(). [updated to fix the bug spotted by Shentino - for SIGSEGV we really need something stronger than send_sig_info(); again, better do that in one place] Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/fs/exec.c b/fs/exec.c
index a2b42a98c743..7302b75a9820 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1372,18 +1372,23 @@ int search_binary_handler(struct linux_binprm *bprm)
read_unlock(&binfmt_lock);
bprm->recursion_depth++;
retval = fmt->load_binary(bprm);
+ read_lock(&binfmt_lock);
+ put_binfmt(fmt);
bprm->recursion_depth--;
- if (retval >= 0 || retval != -ENOEXEC ||
- bprm->mm == NULL || bprm->file == NULL) {
- put_binfmt(fmt);
+ if (retval < 0 && !bprm->mm) {
+ /* we got to flush_old_exec() and failed after it */
+ read_unlock(&binfmt_lock);
+ force_sigsegv(SIGSEGV, current);
+ return retval;
+ }
+ if (retval != -ENOEXEC || !bprm->file) {
+ read_unlock(&binfmt_lock);
return retval;
}
- read_lock(&binfmt_lock);
- put_binfmt(fmt);
}
read_unlock(&binfmt_lock);
- if (need_retry && retval == -ENOEXEC) {
+ if (need_retry) {
if (printable(bprm->buf[0]) && printable(bprm->buf[1]) &&
printable(bprm->buf[2]) && printable(bprm->buf[3]))
return retval;