Commit 19d860a1 authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 29266201
...@@ -308,11 +308,8 @@ static int load_aout_binary(struct linux_binprm *bprm) ...@@ -308,11 +308,8 @@ static int load_aout_binary(struct linux_binprm *bprm)
(current->mm->start_brk = N_BSSADDR(ex)); (current->mm->start_brk = N_BSSADDR(ex));
retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT); retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
if (retval < 0) { if (retval < 0)
/* Someone check-me: is this error path enough? */
send_sig(SIGKILL, current, 0);
return retval; return retval;
}
install_exec_creds(bprm); install_exec_creds(bprm);
...@@ -324,17 +321,13 @@ static int load_aout_binary(struct linux_binprm *bprm) ...@@ -324,17 +321,13 @@ static int load_aout_binary(struct linux_binprm *bprm)
error = vm_brk(text_addr & PAGE_MASK, map_size); error = vm_brk(text_addr & PAGE_MASK, map_size);
if (error != (text_addr & PAGE_MASK)) { if (error != (text_addr & PAGE_MASK))
send_sig(SIGKILL, current, 0);
return error; return error;
}
error = read_code(bprm->file, text_addr, 32, error = read_code(bprm->file, text_addr, 32,
ex.a_text + ex.a_data); ex.a_text + ex.a_data);
if ((signed long)error < 0) { if ((signed long)error < 0)
send_sig(SIGKILL, current, 0);
return error; return error;
}
} else { } else {
#ifdef WARN_OLD #ifdef WARN_OLD
static unsigned long error_time, error_time2; static unsigned long error_time, error_time2;
...@@ -368,20 +361,16 @@ static int load_aout_binary(struct linux_binprm *bprm) ...@@ -368,20 +361,16 @@ static int load_aout_binary(struct linux_binprm *bprm)
MAP_EXECUTABLE | MAP_32BIT, MAP_EXECUTABLE | MAP_32BIT,
fd_offset); fd_offset);
if (error != N_TXTADDR(ex)) { if (error != N_TXTADDR(ex))
send_sig(SIGKILL, current, 0);
return error; return error;
}
error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
MAP_EXECUTABLE | MAP_32BIT, MAP_EXECUTABLE | MAP_32BIT,
fd_offset + ex.a_text); fd_offset + ex.a_text);
if (error != N_DATADDR(ex)) { if (error != N_DATADDR(ex))
send_sig(SIGKILL, current, 0);
return error; return error;
}
} }
beyond_if: beyond_if:
set_binfmt(&aout_format); set_binfmt(&aout_format);
......
...@@ -256,11 +256,8 @@ static int load_aout_binary(struct linux_binprm * bprm) ...@@ -256,11 +256,8 @@ static int load_aout_binary(struct linux_binprm * bprm)
(current->mm->start_brk = N_BSSADDR(ex)); (current->mm->start_brk = N_BSSADDR(ex));
retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
if (retval < 0) { if (retval < 0)
/* Someone check-me: is this error path enough? */
send_sig(SIGKILL, current, 0);
return retval; return retval;
}
install_exec_creds(bprm); install_exec_creds(bprm);
...@@ -278,17 +275,13 @@ static int load_aout_binary(struct linux_binprm * bprm) ...@@ -278,17 +275,13 @@ static int load_aout_binary(struct linux_binprm * bprm)
map_size = ex.a_text+ex.a_data; map_size = ex.a_text+ex.a_data;
#endif #endif
error = vm_brk(text_addr & PAGE_MASK, map_size); error = vm_brk(text_addr & PAGE_MASK, map_size);
if (error != (text_addr & PAGE_MASK)) { if (error != (text_addr & PAGE_MASK))
send_sig(SIGKILL, current, 0);
return error; return error;
}
error = read_code(bprm->file, text_addr, pos, error = read_code(bprm->file, text_addr, pos,
ex.a_text+ex.a_data); ex.a_text+ex.a_data);
if ((signed long)error < 0) { if ((signed long)error < 0)
send_sig(SIGKILL, current, 0);
return error; return error;
}
} else { } else {
if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
(N_MAGIC(ex) != NMAGIC) && printk_ratelimit()) (N_MAGIC(ex) != NMAGIC) && printk_ratelimit())
...@@ -315,28 +308,22 @@ static int load_aout_binary(struct linux_binprm * bprm) ...@@ -315,28 +308,22 @@ static int load_aout_binary(struct linux_binprm * bprm)
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
fd_offset); fd_offset);
if (error != N_TXTADDR(ex)) { if (error != N_TXTADDR(ex))
send_sig(SIGKILL, current, 0);
return error; return error;
}
error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
fd_offset + ex.a_text); fd_offset + ex.a_text);
if (error != N_DATADDR(ex)) { if (error != N_DATADDR(ex))
send_sig(SIGKILL, current, 0);
return error; return error;
}
} }
beyond_if: beyond_if:
set_binfmt(&aout_format); set_binfmt(&aout_format);
retval = set_brk(current->mm->start_brk, current->mm->brk); retval = set_brk(current->mm->start_brk, current->mm->brk);
if (retval < 0) { if (retval < 0)
send_sig(SIGKILL, current, 0);
return retval; return retval;
}
current->mm->start_stack = current->mm->start_stack =
(unsigned long) create_aout_tables((char __user *) bprm->p, bprm); (unsigned long) create_aout_tables((char __user *) bprm->p, bprm);
......
...@@ -738,10 +738,8 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -738,10 +738,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
change some of these later */ change some of these later */
retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
executable_stack); executable_stack);
if (retval < 0) { if (retval < 0)
send_sig(SIGKILL, current, 0);
goto out_free_dentry; goto out_free_dentry;
}
current->mm->start_stack = bprm->p; current->mm->start_stack = bprm->p;
...@@ -763,10 +761,8 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -763,10 +761,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
and clear the area. */ and clear the area. */
retval = set_brk(elf_bss + load_bias, retval = set_brk(elf_bss + load_bias,
elf_brk + load_bias); elf_brk + load_bias);
if (retval) { if (retval)
send_sig(SIGKILL, current, 0);
goto out_free_dentry; goto out_free_dentry;
}
nbyte = ELF_PAGEOFFSET(elf_bss); nbyte = ELF_PAGEOFFSET(elf_bss);
if (nbyte) { if (nbyte) {
nbyte = ELF_MIN_ALIGN - nbyte; nbyte = ELF_MIN_ALIGN - nbyte;
...@@ -820,7 +816,6 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -820,7 +816,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
elf_prot, elf_flags, 0); elf_prot, elf_flags, 0);
if (BAD_ADDR(error)) { if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0);
retval = IS_ERR((void *)error) ? retval = IS_ERR((void *)error) ?
PTR_ERR((void*)error) : -EINVAL; PTR_ERR((void*)error) : -EINVAL;
goto out_free_dentry; goto out_free_dentry;
...@@ -851,7 +846,6 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -851,7 +846,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
elf_ppnt->p_memsz > TASK_SIZE || elf_ppnt->p_memsz > TASK_SIZE ||
TASK_SIZE - elf_ppnt->p_memsz < k) { TASK_SIZE - elf_ppnt->p_memsz < k) {
/* set_brk can never work. Avoid overflows. */ /* set_brk can never work. Avoid overflows. */
send_sig(SIGKILL, current, 0);
retval = -EINVAL; retval = -EINVAL;
goto out_free_dentry; goto out_free_dentry;
} }
...@@ -883,12 +877,9 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -883,12 +877,9 @@ static int load_elf_binary(struct linux_binprm *bprm)
* up getting placed where the bss needs to go. * up getting placed where the bss needs to go.
*/ */
retval = set_brk(elf_bss, elf_brk); retval = set_brk(elf_bss, elf_brk);
if (retval) { if (retval)
send_sig(SIGKILL, current, 0);
goto out_free_dentry; goto out_free_dentry;
}
if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) {
send_sig(SIGSEGV, current, 0);
retval = -EFAULT; /* Nobody gets to see this, but.. */ retval = -EFAULT; /* Nobody gets to see this, but.. */
goto out_free_dentry; goto out_free_dentry;
} }
...@@ -909,7 +900,6 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -909,7 +900,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
elf_entry += loc->interp_elf_ex.e_entry; elf_entry += loc->interp_elf_ex.e_entry;
} }
if (BAD_ADDR(elf_entry)) { if (BAD_ADDR(elf_entry)) {
force_sig(SIGSEGV, current);
retval = IS_ERR((void *)elf_entry) ? retval = IS_ERR((void *)elf_entry) ?
(int)elf_entry : -EINVAL; (int)elf_entry : -EINVAL;
goto out_free_dentry; goto out_free_dentry;
...@@ -922,7 +912,6 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -922,7 +912,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
} else { } else {
elf_entry = loc->elf_ex.e_entry; elf_entry = loc->elf_ex.e_entry;
if (BAD_ADDR(elf_entry)) { if (BAD_ADDR(elf_entry)) {
force_sig(SIGSEGV, current);
retval = -EINVAL; retval = -EINVAL;
goto out_free_dentry; goto out_free_dentry;
} }
...@@ -934,19 +923,15 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -934,19 +923,15 @@ static int load_elf_binary(struct linux_binprm *bprm)
#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
retval = arch_setup_additional_pages(bprm, !!elf_interpreter); retval = arch_setup_additional_pages(bprm, !!elf_interpreter);
if (retval < 0) { if (retval < 0)
send_sig(SIGKILL, current, 0);
goto out; goto out;
}
#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
install_exec_creds(bprm); install_exec_creds(bprm);
retval = create_elf_tables(bprm, &loc->elf_ex, retval = create_elf_tables(bprm, &loc->elf_ex,
load_addr, interp_load_addr); load_addr, interp_load_addr);
if (retval < 0) { if (retval < 0)
send_sig(SIGKILL, current, 0);
goto out; goto out;
}
/* N.B. passed_fileno might not be initialized? */ /* N.B. passed_fileno might not be initialized? */
current->mm->end_code = end_code; current->mm->end_code = end_code;
current->mm->start_code = start_code; current->mm->start_code = start_code;
......
...@@ -317,8 +317,8 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) ...@@ -317,8 +317,8 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
goto error; goto error;
/* there's now no turning back... the old userspace image is dead, /* there's now no turning back... the old userspace image is dead,
* defunct, deceased, etc. after this point we have to exit via * defunct, deceased, etc.
* error_kill */ */
set_personality(PER_LINUX_FDPIC); set_personality(PER_LINUX_FDPIC);
if (elf_read_implies_exec(&exec_params.hdr, executable_stack)) if (elf_read_implies_exec(&exec_params.hdr, executable_stack))
current->personality |= READ_IMPLIES_EXEC; current->personality |= READ_IMPLIES_EXEC;
...@@ -343,24 +343,22 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) ...@@ -343,24 +343,22 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
retval = setup_arg_pages(bprm, current->mm->start_stack, retval = setup_arg_pages(bprm, current->mm->start_stack,
executable_stack); executable_stack);
if (retval < 0) { if (retval < 0)
send_sig(SIGKILL, current, 0); goto error;
goto error_kill;
}
#endif #endif
/* load the executable and interpreter into memory */ /* load the executable and interpreter into memory */
retval = elf_fdpic_map_file(&exec_params, bprm->file, current->mm, retval = elf_fdpic_map_file(&exec_params, bprm->file, current->mm,
"executable"); "executable");
if (retval < 0) if (retval < 0)
goto error_kill; goto error;
if (interpreter_name) { if (interpreter_name) {
retval = elf_fdpic_map_file(&interp_params, interpreter, retval = elf_fdpic_map_file(&interp_params, interpreter,
current->mm, "interpreter"); current->mm, "interpreter");
if (retval < 0) { if (retval < 0) {
printk(KERN_ERR "Unable to load interpreter\n"); printk(KERN_ERR "Unable to load interpreter\n");
goto error_kill; goto error;
} }
allow_write_access(interpreter); allow_write_access(interpreter);
...@@ -397,7 +395,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) ...@@ -397,7 +395,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
if (IS_ERR_VALUE(current->mm->start_brk)) { if (IS_ERR_VALUE(current->mm->start_brk)) {
retval = current->mm->start_brk; retval = current->mm->start_brk;
current->mm->start_brk = 0; current->mm->start_brk = 0;
goto error_kill; goto error;
} }
current->mm->brk = current->mm->start_brk; current->mm->brk = current->mm->start_brk;
...@@ -410,7 +408,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) ...@@ -410,7 +408,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
install_exec_creds(bprm); install_exec_creds(bprm);
if (create_elf_fdpic_tables(bprm, current->mm, if (create_elf_fdpic_tables(bprm, current->mm,
&exec_params, &interp_params) < 0) &exec_params, &interp_params) < 0)
goto error_kill; goto error;
kdebug("- start_code %lx", current->mm->start_code); kdebug("- start_code %lx", current->mm->start_code);
kdebug("- end_code %lx", current->mm->end_code); kdebug("- end_code %lx", current->mm->end_code);
...@@ -449,12 +447,6 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) ...@@ -449,12 +447,6 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
kfree(interp_params.phdrs); kfree(interp_params.phdrs);
kfree(interp_params.loadmap); kfree(interp_params.loadmap);
return retval; return retval;
/* unrecoverable error - kill the process */
error_kill:
send_sig(SIGSEGV, current, 0);
goto error;
} }
/*****************************************************************************/ /*****************************************************************************/
......
...@@ -1372,18 +1372,23 @@ int search_binary_handler(struct linux_binprm *bprm) ...@@ -1372,18 +1372,23 @@ int search_binary_handler(struct linux_binprm *bprm)
read_unlock(&binfmt_lock); read_unlock(&binfmt_lock);
bprm->recursion_depth++; bprm->recursion_depth++;
retval = fmt->load_binary(bprm); retval = fmt->load_binary(bprm);
read_lock(&binfmt_lock);
put_binfmt(fmt);
bprm->recursion_depth--; bprm->recursion_depth--;
if (retval >= 0 || retval != -ENOEXEC || if (retval < 0 && !bprm->mm) {
bprm->mm == NULL || bprm->file == NULL) { /* we got to flush_old_exec() and failed after it */
put_binfmt(fmt); read_unlock(&binfmt_lock);
force_sigsegv(SIGSEGV, current);
return retval;
}
if (retval != -ENOEXEC || !bprm->file) {
read_unlock(&binfmt_lock);
return retval; return retval;
} }
read_lock(&binfmt_lock);
put_binfmt(fmt);
} }
read_unlock(&binfmt_lock); read_unlock(&binfmt_lock);
if (need_retry && retval == -ENOEXEC) { if (need_retry) {
if (printable(bprm->buf[0]) && printable(bprm->buf[1]) && if (printable(bprm->buf[0]) && printable(bprm->buf[1]) &&
printable(bprm->buf[2]) && printable(bprm->buf[3])) printable(bprm->buf[2]) && printable(bprm->buf[3]))
return retval; return retval;
......
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