diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-05-04 20:11:36 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-10-09 02:39:00 -0400 |
commit | 19d860a140beac48a1377f179e693abe86a9dac9 (patch) | |
tree | 4da809a162a3b9aea8575828f52e150b26ca6ff1 | |
parent | 2926620145095ffb0350b2312ac9d0af8537796f (diff) |
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>
-rw-r--r-- | arch/x86/ia32/ia32_aout.c | 21 | ||||
-rw-r--r-- | fs/binfmt_aout.c | 25 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 25 | ||||
-rw-r--r-- | fs/binfmt_elf_fdpic.c | 24 | ||||
-rw-r--r-- | fs/exec.c | 17 |
5 files changed, 35 insertions, 77 deletions
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index d21ff89207cd..df91466f973d 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c | |||
@@ -308,11 +308,8 @@ static int load_aout_binary(struct linux_binprm *bprm) | |||
308 | (current->mm->start_brk = N_BSSADDR(ex)); | 308 | (current->mm->start_brk = N_BSSADDR(ex)); |
309 | 309 | ||
310 | retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT); | 310 | retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT); |
311 | if (retval < 0) { | 311 | if (retval < 0) |
312 | /* Someone check-me: is this error path enough? */ | ||
313 | send_sig(SIGKILL, current, 0); | ||
314 | return retval; | 312 | return retval; |
315 | } | ||
316 | 313 | ||
317 | install_exec_creds(bprm); | 314 | install_exec_creds(bprm); |
318 | 315 | ||
@@ -324,17 +321,13 @@ static int load_aout_binary(struct linux_binprm *bprm) | |||
324 | 321 | ||
325 | error = vm_brk(text_addr & PAGE_MASK, map_size); | 322 | error = vm_brk(text_addr & PAGE_MASK, map_size); |
326 | 323 | ||
327 | if (error != (text_addr & PAGE_MASK)) { | 324 | if (error != (text_addr & PAGE_MASK)) |
328 | send_sig(SIGKILL, current, 0); | ||
329 | return error; | 325 | return error; |
330 | } | ||
331 | 326 | ||
332 | error = read_code(bprm->file, text_addr, 32, | 327 | error = read_code(bprm->file, text_addr, 32, |
333 | ex.a_text + ex.a_data); | 328 | ex.a_text + ex.a_data); |
334 | if ((signed long)error < 0) { | 329 | if ((signed long)error < 0) |
335 | send_sig(SIGKILL, current, 0); | ||
336 | return error; | 330 | return error; |
337 | } | ||
338 | } else { | 331 | } else { |
339 | #ifdef WARN_OLD | 332 | #ifdef WARN_OLD |
340 | static unsigned long error_time, error_time2; | 333 | static unsigned long error_time, error_time2; |
@@ -368,20 +361,16 @@ static int load_aout_binary(struct linux_binprm *bprm) | |||
368 | MAP_EXECUTABLE | MAP_32BIT, | 361 | MAP_EXECUTABLE | MAP_32BIT, |
369 | fd_offset); | 362 | fd_offset); |
370 | 363 | ||
371 | if (error != N_TXTADDR(ex)) { | 364 | if (error != N_TXTADDR(ex)) |
372 | send_sig(SIGKILL, current, 0); | ||
373 | return error; | 365 | return error; |
374 | } | ||
375 | 366 | ||
376 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, | 367 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, |
377 | PROT_READ | PROT_WRITE | PROT_EXEC, | 368 | PROT_READ | PROT_WRITE | PROT_EXEC, |
378 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | | 369 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | |
379 | MAP_EXECUTABLE | MAP_32BIT, | 370 | MAP_EXECUTABLE | MAP_32BIT, |
380 | fd_offset + ex.a_text); | 371 | fd_offset + ex.a_text); |
381 | if (error != N_DATADDR(ex)) { | 372 | if (error != N_DATADDR(ex)) |
382 | send_sig(SIGKILL, current, 0); | ||
383 | return error; | 373 | return error; |
384 | } | ||
385 | } | 374 | } |
386 | beyond_if: | 375 | beyond_if: |
387 | set_binfmt(&aout_format); | 376 | set_binfmt(&aout_format); |
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index ca0ba15a7306..929dec08c348 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c | |||
@@ -256,11 +256,8 @@ static int load_aout_binary(struct linux_binprm * bprm) | |||
256 | (current->mm->start_brk = N_BSSADDR(ex)); | 256 | (current->mm->start_brk = N_BSSADDR(ex)); |
257 | 257 | ||
258 | retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); | 258 | retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); |
259 | if (retval < 0) { | 259 | if (retval < 0) |
260 | /* Someone check-me: is this error path enough? */ | ||
261 | send_sig(SIGKILL, current, 0); | ||
262 | return retval; | 260 | return retval; |
263 | } | ||
264 | 261 | ||
265 | install_exec_creds(bprm); | 262 | install_exec_creds(bprm); |
266 | 263 | ||
@@ -278,17 +275,13 @@ static int load_aout_binary(struct linux_binprm * bprm) | |||
278 | map_size = ex.a_text+ex.a_data; | 275 | map_size = ex.a_text+ex.a_data; |
279 | #endif | 276 | #endif |
280 | error = vm_brk(text_addr & PAGE_MASK, map_size); | 277 | error = vm_brk(text_addr & PAGE_MASK, map_size); |
281 | if (error != (text_addr & PAGE_MASK)) { | 278 | if (error != (text_addr & PAGE_MASK)) |
282 | send_sig(SIGKILL, current, 0); | ||
283 | return error; | 279 | return error; |
284 | } | ||
285 | 280 | ||
286 | error = read_code(bprm->file, text_addr, pos, | 281 | error = read_code(bprm->file, text_addr, pos, |
287 | ex.a_text+ex.a_data); | 282 | ex.a_text+ex.a_data); |
288 | if ((signed long)error < 0) { | 283 | if ((signed long)error < 0) |
289 | send_sig(SIGKILL, current, 0); | ||
290 | return error; | 284 | return error; |
291 | } | ||
292 | } else { | 285 | } else { |
293 | if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && | 286 | if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && |
294 | (N_MAGIC(ex) != NMAGIC) && printk_ratelimit()) | 287 | (N_MAGIC(ex) != NMAGIC) && printk_ratelimit()) |
@@ -315,28 +308,22 @@ static int load_aout_binary(struct linux_binprm * bprm) | |||
315 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, | 308 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, |
316 | fd_offset); | 309 | fd_offset); |
317 | 310 | ||
318 | if (error != N_TXTADDR(ex)) { | 311 | if (error != N_TXTADDR(ex)) |
319 | send_sig(SIGKILL, current, 0); | ||
320 | return error; | 312 | return error; |
321 | } | ||
322 | 313 | ||
323 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, | 314 | error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data, |
324 | PROT_READ | PROT_WRITE | PROT_EXEC, | 315 | PROT_READ | PROT_WRITE | PROT_EXEC, |
325 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, | 316 | MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, |
326 | fd_offset + ex.a_text); | 317 | fd_offset + ex.a_text); |
327 | if (error != N_DATADDR(ex)) { | 318 | if (error != N_DATADDR(ex)) |
328 | send_sig(SIGKILL, current, 0); | ||
329 | return error; | 319 | return error; |
330 | } | ||
331 | } | 320 | } |
332 | beyond_if: | 321 | beyond_if: |
333 | set_binfmt(&aout_format); | 322 | set_binfmt(&aout_format); |
334 | 323 | ||
335 | retval = set_brk(current->mm->start_brk, current->mm->brk); | 324 | retval = set_brk(current->mm->start_brk, current->mm->brk); |
336 | if (retval < 0) { | 325 | if (retval < 0) |
337 | send_sig(SIGKILL, current, 0); | ||
338 | return retval; | 326 | return retval; |
339 | } | ||
340 | 327 | ||
341 | current->mm->start_stack = | 328 | current->mm->start_stack = |
342 | (unsigned long) create_aout_tables((char __user *) bprm->p, bprm); | 329 | (unsigned long) create_aout_tables((char __user *) bprm->p, bprm); |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 3892c1a23241..d8fc0605b9d2 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -738,10 +738,8 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
738 | change some of these later */ | 738 | change some of these later */ |
739 | retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), | 739 | retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), |
740 | executable_stack); | 740 | executable_stack); |
741 | if (retval < 0) { | 741 | if (retval < 0) |
742 | send_sig(SIGKILL, current, 0); | ||
743 | goto out_free_dentry; | 742 | goto out_free_dentry; |
744 | } | ||
745 | 743 | ||
746 | current->mm->start_stack = bprm->p; | 744 | current->mm->start_stack = bprm->p; |
747 | 745 | ||
@@ -763,10 +761,8 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
763 | and clear the area. */ | 761 | and clear the area. */ |
764 | retval = set_brk(elf_bss + load_bias, | 762 | retval = set_brk(elf_bss + load_bias, |
765 | elf_brk + load_bias); | 763 | elf_brk + load_bias); |
766 | if (retval) { | 764 | if (retval) |
767 | send_sig(SIGKILL, current, 0); | ||
768 | goto out_free_dentry; | 765 | goto out_free_dentry; |
769 | } | ||
770 | nbyte = ELF_PAGEOFFSET(elf_bss); | 766 | nbyte = ELF_PAGEOFFSET(elf_bss); |
771 | if (nbyte) { | 767 | if (nbyte) { |
772 | nbyte = ELF_MIN_ALIGN - nbyte; | 768 | nbyte = ELF_MIN_ALIGN - nbyte; |
@@ -820,7 +816,6 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
820 | error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, | 816 | error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, |
821 | elf_prot, elf_flags, 0); | 817 | elf_prot, elf_flags, 0); |
822 | if (BAD_ADDR(error)) { | 818 | if (BAD_ADDR(error)) { |
823 | send_sig(SIGKILL, current, 0); | ||
824 | retval = IS_ERR((void *)error) ? | 819 | retval = IS_ERR((void *)error) ? |
825 | PTR_ERR((void*)error) : -EINVAL; | 820 | PTR_ERR((void*)error) : -EINVAL; |
826 | goto out_free_dentry; | 821 | goto out_free_dentry; |
@@ -851,7 +846,6 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
851 | elf_ppnt->p_memsz > TASK_SIZE || | 846 | elf_ppnt->p_memsz > TASK_SIZE || |
852 | TASK_SIZE - elf_ppnt->p_memsz < k) { | 847 | TASK_SIZE - elf_ppnt->p_memsz < k) { |
853 | /* set_brk can never work. Avoid overflows. */ | 848 | /* set_brk can never work. Avoid overflows. */ |
854 | send_sig(SIGKILL, current, 0); | ||
855 | retval = -EINVAL; | 849 | retval = -EINVAL; |
856 | goto out_free_dentry; | 850 | goto out_free_dentry; |
857 | } | 851 | } |
@@ -883,12 +877,9 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
883 | * up getting placed where the bss needs to go. | 877 | * up getting placed where the bss needs to go. |
884 | */ | 878 | */ |
885 | retval = set_brk(elf_bss, elf_brk); | 879 | retval = set_brk(elf_bss, elf_brk); |
886 | if (retval) { | 880 | if (retval) |
887 | send_sig(SIGKILL, current, 0); | ||
888 | goto out_free_dentry; | 881 | goto out_free_dentry; |
889 | } | ||
890 | if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { | 882 | if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { |
891 | send_sig(SIGSEGV, current, 0); | ||
892 | retval = -EFAULT; /* Nobody gets to see this, but.. */ | 883 | retval = -EFAULT; /* Nobody gets to see this, but.. */ |
893 | goto out_free_dentry; | 884 | goto out_free_dentry; |
894 | } | 885 | } |
@@ -909,7 +900,6 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
909 | elf_entry += loc->interp_elf_ex.e_entry; | 900 | elf_entry += loc->interp_elf_ex.e_entry; |
910 | } | 901 | } |
911 | if (BAD_ADDR(elf_entry)) { | 902 | if (BAD_ADDR(elf_entry)) { |
912 | force_sig(SIGSEGV, current); | ||
913 | retval = IS_ERR((void *)elf_entry) ? | 903 | retval = IS_ERR((void *)elf_entry) ? |
914 | (int)elf_entry : -EINVAL; | 904 | (int)elf_entry : -EINVAL; |
915 | goto out_free_dentry; | 905 | goto out_free_dentry; |
@@ -922,7 +912,6 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
922 | } else { | 912 | } else { |
923 | elf_entry = loc->elf_ex.e_entry; | 913 | elf_entry = loc->elf_ex.e_entry; |
924 | if (BAD_ADDR(elf_entry)) { | 914 | if (BAD_ADDR(elf_entry)) { |
925 | force_sig(SIGSEGV, current); | ||
926 | retval = -EINVAL; | 915 | retval = -EINVAL; |
927 | goto out_free_dentry; | 916 | goto out_free_dentry; |
928 | } | 917 | } |
@@ -934,19 +923,15 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
934 | 923 | ||
935 | #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES | 924 | #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES |
936 | retval = arch_setup_additional_pages(bprm, !!elf_interpreter); | 925 | retval = arch_setup_additional_pages(bprm, !!elf_interpreter); |
937 | if (retval < 0) { | 926 | if (retval < 0) |
938 | send_sig(SIGKILL, current, 0); | ||
939 | goto out; | 927 | goto out; |
940 | } | ||
941 | #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ | 928 | #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ |
942 | 929 | ||
943 | install_exec_creds(bprm); | 930 | install_exec_creds(bprm); |
944 | retval = create_elf_tables(bprm, &loc->elf_ex, | 931 | retval = create_elf_tables(bprm, &loc->elf_ex, |
945 | load_addr, interp_load_addr); | 932 | load_addr, interp_load_addr); |
946 | if (retval < 0) { | 933 | if (retval < 0) |
947 | send_sig(SIGKILL, current, 0); | ||
948 | goto out; | 934 | goto out; |
949 | } | ||
950 | /* N.B. passed_fileno might not be initialized? */ | 935 | /* N.B. passed_fileno might not be initialized? */ |
951 | current->mm->end_code = end_code; | 936 | current->mm->end_code = end_code; |
952 | current->mm->start_code = start_code; | 937 | current->mm->start_code = start_code; |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index fe2a643ee005..d3634bfb7fe1 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -317,8 +317,8 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) | |||
317 | goto error; | 317 | goto error; |
318 | 318 | ||
319 | /* there's now no turning back... the old userspace image is dead, | 319 | /* there's now no turning back... the old userspace image is dead, |
320 | * defunct, deceased, etc. after this point we have to exit via | 320 | * defunct, deceased, etc. |
321 | * error_kill */ | 321 | */ |
322 | set_personality(PER_LINUX_FDPIC); | 322 | set_personality(PER_LINUX_FDPIC); |
323 | if (elf_read_implies_exec(&exec_params.hdr, executable_stack)) | 323 | if (elf_read_implies_exec(&exec_params.hdr, executable_stack)) |
324 | current->personality |= READ_IMPLIES_EXEC; | 324 | current->personality |= READ_IMPLIES_EXEC; |
@@ -343,24 +343,22 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) | |||
343 | 343 | ||
344 | retval = setup_arg_pages(bprm, current->mm->start_stack, | 344 | retval = setup_arg_pages(bprm, current->mm->start_stack, |
345 | executable_stack); | 345 | executable_stack); |
346 | if (retval < 0) { | 346 | if (retval < 0) |
347 | send_sig(SIGKILL, current, 0); | 347 | goto error; |
348 | goto error_kill; | ||
349 | } | ||
350 | #endif | 348 | #endif |
351 | 349 | ||
352 | /* load the executable and interpreter into memory */ | 350 | /* load the executable and interpreter into memory */ |
353 | retval = elf_fdpic_map_file(&exec_params, bprm->file, current->mm, | 351 | retval = elf_fdpic_map_file(&exec_params, bprm->file, current->mm, |
354 | "executable"); | 352 | "executable"); |
355 | if (retval < 0) | 353 | if (retval < 0) |
356 | goto error_kill; | 354 | goto error; |
357 | 355 | ||
358 | if (interpreter_name) { | 356 | if (interpreter_name) { |
359 | retval = elf_fdpic_map_file(&interp_params, interpreter, | 357 | retval = elf_fdpic_map_file(&interp_params, interpreter, |
360 | current->mm, "interpreter"); | 358 | current->mm, "interpreter"); |
361 | if (retval < 0) { | 359 | if (retval < 0) { |
362 | printk(KERN_ERR "Unable to load interpreter\n"); | 360 | printk(KERN_ERR "Unable to load interpreter\n"); |
363 | goto error_kill; | 361 | goto error; |
364 | } | 362 | } |
365 | 363 | ||
366 | allow_write_access(interpreter); | 364 | allow_write_access(interpreter); |
@@ -397,7 +395,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) | |||
397 | if (IS_ERR_VALUE(current->mm->start_brk)) { | 395 | if (IS_ERR_VALUE(current->mm->start_brk)) { |
398 | retval = current->mm->start_brk; | 396 | retval = current->mm->start_brk; |
399 | current->mm->start_brk = 0; | 397 | current->mm->start_brk = 0; |
400 | goto error_kill; | 398 | goto error; |
401 | } | 399 | } |
402 | 400 | ||
403 | current->mm->brk = current->mm->start_brk; | 401 | current->mm->brk = current->mm->start_brk; |
@@ -410,7 +408,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) | |||
410 | install_exec_creds(bprm); | 408 | install_exec_creds(bprm); |
411 | if (create_elf_fdpic_tables(bprm, current->mm, | 409 | if (create_elf_fdpic_tables(bprm, current->mm, |
412 | &exec_params, &interp_params) < 0) | 410 | &exec_params, &interp_params) < 0) |
413 | goto error_kill; | 411 | goto error; |
414 | 412 | ||
415 | kdebug("- start_code %lx", current->mm->start_code); | 413 | kdebug("- start_code %lx", current->mm->start_code); |
416 | kdebug("- end_code %lx", current->mm->end_code); | 414 | kdebug("- end_code %lx", current->mm->end_code); |
@@ -449,12 +447,6 @@ error: | |||
449 | kfree(interp_params.phdrs); | 447 | kfree(interp_params.phdrs); |
450 | kfree(interp_params.loadmap); | 448 | kfree(interp_params.loadmap); |
451 | return retval; | 449 | return retval; |
452 | |||
453 | /* unrecoverable error - kill the process */ | ||
454 | error_kill: | ||
455 | send_sig(SIGSEGV, current, 0); | ||
456 | goto error; | ||
457 | |||
458 | } | 450 | } |
459 | 451 | ||
460 | /*****************************************************************************/ | 452 | /*****************************************************************************/ |
@@ -1372,18 +1372,23 @@ int search_binary_handler(struct linux_binprm *bprm) | |||
1372 | read_unlock(&binfmt_lock); | 1372 | read_unlock(&binfmt_lock); |
1373 | bprm->recursion_depth++; | 1373 | bprm->recursion_depth++; |
1374 | retval = fmt->load_binary(bprm); | 1374 | retval = fmt->load_binary(bprm); |
1375 | read_lock(&binfmt_lock); | ||
1376 | put_binfmt(fmt); | ||
1375 | bprm->recursion_depth--; | 1377 | bprm->recursion_depth--; |
1376 | if (retval >= 0 || retval != -ENOEXEC || | 1378 | if (retval < 0 && !bprm->mm) { |
1377 | bprm->mm == NULL || bprm->file == NULL) { | 1379 | /* we got to flush_old_exec() and failed after it */ |
1378 | put_binfmt(fmt); | 1380 | read_unlock(&binfmt_lock); |
1381 | force_sigsegv(SIGSEGV, current); | ||
1382 | return retval; | ||
1383 | } | ||
1384 | if (retval != -ENOEXEC || !bprm->file) { | ||
1385 | read_unlock(&binfmt_lock); | ||
1379 | return retval; | 1386 | return retval; |
1380 | } | 1387 | } |
1381 | read_lock(&binfmt_lock); | ||
1382 | put_binfmt(fmt); | ||
1383 | } | 1388 | } |
1384 | read_unlock(&binfmt_lock); | 1389 | read_unlock(&binfmt_lock); |
1385 | 1390 | ||
1386 | if (need_retry && retval == -ENOEXEC) { | 1391 | if (need_retry) { |
1387 | if (printable(bprm->buf[0]) && printable(bprm->buf[1]) && | 1392 | if (printable(bprm->buf[0]) && printable(bprm->buf[1]) && |
1388 | printable(bprm->buf[2]) && printable(bprm->buf[3])) | 1393 | printable(bprm->buf[2]) && printable(bprm->buf[3])) |
1389 | return retval; | 1394 | return retval; |