diff options
| -rw-r--r-- | arch/Kconfig | 3 | ||||
| -rw-r--r-- | arch/alpha/Kconfig | 1 | ||||
| -rw-r--r-- | arch/alpha/include/asm/unistd.h | 1 | ||||
| -rw-r--r-- | arch/alpha/kernel/entry.S | 87 | ||||
| -rw-r--r-- | arch/alpha/kernel/signal.c | 48 | ||||
| -rw-r--r-- | arch/arm/Kconfig | 1 | ||||
| -rw-r--r-- | arch/arm/include/asm/unistd.h | 1 | ||||
| -rw-r--r-- | arch/arm/kernel/entry-common.S | 29 | ||||
| -rw-r--r-- | arch/arm/kernel/process.c | 5 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/eeh_event.c | 5 | ||||
| -rw-r--r-- | arch/um/include/asm/processor-generic.h | 2 | ||||
| -rw-r--r-- | arch/um/include/shared/os.h | 1 | ||||
| -rw-r--r-- | arch/um/kernel/exec.c | 5 | ||||
| -rw-r--r-- | arch/um/kernel/process.c | 10 | ||||
| -rw-r--r-- | arch/um/os-Linux/process.c | 13 | ||||
| -rw-r--r-- | arch/x86/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/unistd.h | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_32.S | 31 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_64.S | 24 | ||||
| -rw-r--r-- | arch/x86/um/Kconfig | 1 | ||||
| -rw-r--r-- | include/linux/syscalls.h | 8 | ||||
| -rw-r--r-- | init/do_mounts_initrd.c | 41 | ||||
| -rw-r--r-- | init/main.c | 33 | ||||
| -rw-r--r-- | kernel/kmod.c | 7 | ||||
| -rw-r--r-- | kernel/kthread.c | 1 |
25 files changed, 137 insertions, 223 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 26a28419cafc..a79a1ad8bb96 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
| @@ -274,6 +274,9 @@ config ARCH_WANT_OLD_COMPAT_IPC | |||
| 274 | config GENERIC_KERNEL_THREAD | 274 | config GENERIC_KERNEL_THREAD |
| 275 | bool | 275 | bool |
| 276 | 276 | ||
| 277 | config GENERIC_KERNEL_EXECVE | ||
| 278 | bool | ||
| 279 | |||
| 277 | config HAVE_ARCH_SECCOMP_FILTER | 280 | config HAVE_ARCH_SECCOMP_FILTER |
| 278 | bool | 281 | bool |
| 279 | help | 282 | help |
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 7da91246e279..7a08cfb80ee8 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig | |||
| @@ -21,6 +21,7 @@ config ALPHA | |||
| 21 | select GENERIC_STRNCPY_FROM_USER | 21 | select GENERIC_STRNCPY_FROM_USER |
| 22 | select GENERIC_STRNLEN_USER | 22 | select GENERIC_STRNLEN_USER |
| 23 | select GENERIC_KERNEL_THREAD | 23 | select GENERIC_KERNEL_THREAD |
| 24 | select GENERIC_KERNEL_EXECVE | ||
| 24 | help | 25 | help |
| 25 | The Alpha is a 64-bit general-purpose processor designed and | 26 | The Alpha is a 64-bit general-purpose processor designed and |
| 26 | marketed by the Digital Equipment Corporation of blessed memory, | 27 | marketed by the Digital Equipment Corporation of blessed memory, |
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index 3cb6c1188984..7826e227e4d0 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h | |||
| @@ -482,7 +482,6 @@ | |||
| 482 | #define __ARCH_WANT_SYS_SIGPENDING | 482 | #define __ARCH_WANT_SYS_SIGPENDING |
| 483 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 483 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
| 484 | #define __ARCH_WANT_SYS_EXECVE | 484 | #define __ARCH_WANT_SYS_EXECVE |
| 485 | #define __ARCH_WANT_KERNEL_EXECVE | ||
| 486 | 485 | ||
| 487 | /* "Conditional" syscalls. What we want is | 486 | /* "Conditional" syscalls. What we want is |
| 488 | 487 | ||
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 2a359c9ee3cd..a7607832dd4f 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S | |||
| @@ -311,7 +311,7 @@ entSys: | |||
| 311 | 311 | ||
| 312 | .align 4 | 312 | .align 4 |
| 313 | ret_from_sys_call: | 313 | ret_from_sys_call: |
| 314 | cmovne $26, 0, $19 /* $19 = 0 => non-restartable */ | 314 | cmovne $26, 0, $18 /* $18 = 0 => non-restartable */ |
| 315 | ldq $0, SP_OFF($sp) | 315 | ldq $0, SP_OFF($sp) |
| 316 | and $0, 8, $0 | 316 | and $0, 8, $0 |
| 317 | beq $0, ret_to_kernel | 317 | beq $0, ret_to_kernel |
| @@ -320,8 +320,8 @@ ret_to_user: | |||
| 320 | sampling and the rti. */ | 320 | sampling and the rti. */ |
| 321 | lda $16, 7 | 321 | lda $16, 7 |
| 322 | call_pal PAL_swpipl | 322 | call_pal PAL_swpipl |
| 323 | ldl $5, TI_FLAGS($8) | 323 | ldl $17, TI_FLAGS($8) |
| 324 | and $5, _TIF_WORK_MASK, $2 | 324 | and $17, _TIF_WORK_MASK, $2 |
| 325 | bne $2, work_pending | 325 | bne $2, work_pending |
| 326 | restore_all: | 326 | restore_all: |
| 327 | RESTORE_ALL | 327 | RESTORE_ALL |
| @@ -341,10 +341,10 @@ $syscall_error: | |||
| 341 | * frame to indicate that a negative return value wasn't an | 341 | * frame to indicate that a negative return value wasn't an |
| 342 | * error number.. | 342 | * error number.. |
| 343 | */ | 343 | */ |
| 344 | ldq $19, 0($sp) /* old syscall nr (zero if success) */ | 344 | ldq $18, 0($sp) /* old syscall nr (zero if success) */ |
| 345 | beq $19, $ret_success | 345 | beq $18, $ret_success |
| 346 | 346 | ||
| 347 | ldq $20, 72($sp) /* .. and this a3 */ | 347 | ldq $19, 72($sp) /* .. and this a3 */ |
| 348 | subq $31, $0, $0 /* with error in v0 */ | 348 | subq $31, $0, $0 /* with error in v0 */ |
| 349 | addq $31, 1, $1 /* set a3 for errno return */ | 349 | addq $31, 1, $1 /* set a3 for errno return */ |
| 350 | stq $0, 0($sp) | 350 | stq $0, 0($sp) |
| @@ -362,51 +362,35 @@ $ret_success: | |||
| 362 | * Do all cleanup when returning from all interrupts and system calls. | 362 | * Do all cleanup when returning from all interrupts and system calls. |
| 363 | * | 363 | * |
| 364 | * Arguments: | 364 | * Arguments: |
| 365 | * $5: TI_FLAGS. | ||
| 366 | * $8: current. | 365 | * $8: current. |
| 367 | * $19: The old syscall number, or zero if this is not a return | 366 | * $17: TI_FLAGS. |
| 367 | * $18: The old syscall number, or zero if this is not a return | ||
| 368 | * from a syscall that errored and is possibly restartable. | 368 | * from a syscall that errored and is possibly restartable. |
| 369 | * $20: The old a3 value | 369 | * $19: The old a3 value |
| 370 | */ | 370 | */ |
| 371 | 371 | ||
| 372 | .align 4 | 372 | .align 4 |
| 373 | .ent work_pending | 373 | .ent work_pending |
| 374 | work_pending: | 374 | work_pending: |
| 375 | and $5, _TIF_NEED_RESCHED, $2 | 375 | and $17, _TIF_NOTIFY_RESUME | _TIF_SIGPENDING, $2 |
| 376 | beq $2, $work_notifysig | 376 | bne $2, $work_notifysig |
| 377 | 377 | ||
| 378 | $work_resched: | 378 | $work_resched: |
| 379 | subq $sp, 16, $sp | 379 | /* |
| 380 | stq $19, 0($sp) /* save syscall nr */ | 380 | * We can get here only if we returned from syscall without SIGPENDING |
| 381 | stq $20, 8($sp) /* and error indication (a3) */ | 381 | * or got through work_notifysig already. Either case means no syscall |
| 382 | * restarts for us, so let $18 and $19 burn. | ||
| 383 | */ | ||
| 382 | jsr $26, schedule | 384 | jsr $26, schedule |
| 383 | ldq $19, 0($sp) | 385 | mov 0, $18 |
| 384 | ldq $20, 8($sp) | 386 | br ret_to_user |
| 385 | addq $sp, 16, $sp | ||
| 386 | /* Make sure need_resched and sigpending don't change between | ||
| 387 | sampling and the rti. */ | ||
| 388 | lda $16, 7 | ||
| 389 | call_pal PAL_swpipl | ||
| 390 | ldl $5, TI_FLAGS($8) | ||
| 391 | and $5, _TIF_WORK_MASK, $2 | ||
| 392 | beq $2, restore_all | ||
| 393 | and $5, _TIF_NEED_RESCHED, $2 | ||
| 394 | bne $2, $work_resched | ||
| 395 | 387 | ||
| 396 | $work_notifysig: | 388 | $work_notifysig: |
| 397 | mov $sp, $16 | 389 | mov $sp, $16 |
| 398 | bsr $1, do_switch_stack | 390 | bsr $1, do_switch_stack |
| 399 | mov $sp, $17 | 391 | jsr $26, do_work_pending |
| 400 | mov $5, $18 | ||
| 401 | mov $19, $9 /* save old syscall number */ | ||
| 402 | mov $20, $10 /* save old a3 */ | ||
| 403 | and $5, _TIF_SIGPENDING, $2 | ||
| 404 | cmovne $2, 0, $9 /* we don't want double syscall restarts */ | ||
| 405 | jsr $26, do_notify_resume | ||
| 406 | mov $9, $19 | ||
| 407 | mov $10, $20 | ||
| 408 | bsr $1, undo_switch_stack | 392 | bsr $1, undo_switch_stack |
| 409 | br ret_to_user | 393 | br restore_all |
| 410 | .end work_pending | 394 | .end work_pending |
| 411 | 395 | ||
| 412 | /* | 396 | /* |
| @@ -454,9 +438,9 @@ $strace_success: | |||
| 454 | 438 | ||
| 455 | .align 3 | 439 | .align 3 |
| 456 | $strace_error: | 440 | $strace_error: |
| 457 | ldq $19, 0($sp) /* old syscall nr (zero if success) */ | 441 | ldq $18, 0($sp) /* old syscall nr (zero if success) */ |
| 458 | beq $19, $strace_success | 442 | beq $18, $strace_success |
| 459 | ldq $20, 72($sp) /* .. and this a3 */ | 443 | ldq $19, 72($sp) /* .. and this a3 */ |
| 460 | 444 | ||
| 461 | subq $31, $0, $0 /* with error in v0 */ | 445 | subq $31, $0, $0 /* with error in v0 */ |
| 462 | addq $31, 1, $1 /* set a3 for errno return */ | 446 | addq $31, 1, $1 /* set a3 for errno return */ |
| @@ -464,11 +448,11 @@ $strace_error: | |||
| 464 | stq $1, 72($sp) /* a3 for return */ | 448 | stq $1, 72($sp) /* a3 for return */ |
| 465 | 449 | ||
| 466 | bsr $1, do_switch_stack | 450 | bsr $1, do_switch_stack |
| 467 | mov $19, $9 /* save old syscall number */ | 451 | mov $18, $9 /* save old syscall number */ |
| 468 | mov $20, $10 /* save old a3 */ | 452 | mov $19, $10 /* save old a3 */ |
| 469 | jsr $26, syscall_trace_leave | 453 | jsr $26, syscall_trace_leave |
| 470 | mov $9, $19 | 454 | mov $9, $18 |
| 471 | mov $10, $20 | 455 | mov $10, $19 |
| 472 | bsr $1, undo_switch_stack | 456 | bsr $1, undo_switch_stack |
| 473 | 457 | ||
| 474 | mov $31, $26 /* tell "ret_from_sys_call" we can restart */ | 458 | mov $31, $26 /* tell "ret_from_sys_call" we can restart */ |
| @@ -619,24 +603,9 @@ ret_from_kernel_thread: | |||
| 619 | mov $9, $27 | 603 | mov $9, $27 |
| 620 | mov $10, $16 | 604 | mov $10, $16 |
| 621 | jsr $26, ($9) | 605 | jsr $26, ($9) |
| 622 | ldgp $gp, 0($26) | ||
| 623 | mov $0, $16 | ||
| 624 | mov $31, $26 | ||
| 625 | jmp $31, sys_exit | ||
| 626 | .end ret_from_kernel_thread | ||
| 627 | |||
| 628 | .globl ret_from_kernel_execve | ||
| 629 | .align 4 | ||
| 630 | .ent ret_from_kernel_execve | ||
| 631 | ret_from_kernel_execve: | ||
| 632 | mov $16, $sp | ||
| 633 | /* Avoid the HAE being gratuitously wrong, to avoid restoring it. */ | ||
| 634 | ldq $2, alpha_mv+HAE_CACHE | ||
| 635 | stq $2, 152($sp) /* HAE */ | ||
| 636 | mov $31, $19 /* to disable syscall restarts */ | 606 | mov $31, $19 /* to disable syscall restarts */ |
| 637 | br $31, ret_to_user | 607 | br $31, ret_to_user |
| 638 | 608 | .end ret_from_kernel_thread | |
| 639 | .end ret_from_kernel_execve | ||
| 640 | 609 | ||
| 641 | 610 | ||
| 642 | /* | 611 | /* |
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index a8c97d42ec8e..32575f85507d 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c | |||
| @@ -298,8 +298,9 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | |||
| 298 | 298 | ||
| 299 | static long | 299 | static long |
| 300 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | 300 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
| 301 | struct switch_stack *sw, unsigned long mask, unsigned long sp) | 301 | unsigned long mask, unsigned long sp) |
| 302 | { | 302 | { |
| 303 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
| 303 | long i, err = 0; | 304 | long i, err = 0; |
| 304 | 305 | ||
| 305 | err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack); | 306 | err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack); |
| @@ -354,7 +355,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
| 354 | 355 | ||
| 355 | static int | 356 | static int |
| 356 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 357 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
| 357 | struct pt_regs *regs, struct switch_stack * sw) | 358 | struct pt_regs *regs) |
| 358 | { | 359 | { |
| 359 | unsigned long oldsp, r26, err = 0; | 360 | unsigned long oldsp, r26, err = 0; |
| 360 | struct sigframe __user *frame; | 361 | struct sigframe __user *frame; |
| @@ -364,7 +365,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
| 364 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 365 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 365 | return -EFAULT; | 366 | return -EFAULT; |
| 366 | 367 | ||
| 367 | err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); | 368 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp); |
| 368 | if (err) | 369 | if (err) |
| 369 | return -EFAULT; | 370 | return -EFAULT; |
| 370 | 371 | ||
| @@ -401,7 +402,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
| 401 | 402 | ||
| 402 | static int | 403 | static int |
| 403 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 404 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 404 | sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) | 405 | sigset_t *set, struct pt_regs *regs) |
| 405 | { | 406 | { |
| 406 | unsigned long oldsp, r26, err = 0; | 407 | unsigned long oldsp, r26, err = 0; |
| 407 | struct rt_sigframe __user *frame; | 408 | struct rt_sigframe __user *frame; |
| @@ -420,7 +421,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 420 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 421 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
| 421 | err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags); | 422 | err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags); |
| 422 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 423 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 423 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, | 424 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, |
| 424 | set->sig[0], oldsp); | 425 | set->sig[0], oldsp); |
| 425 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 426 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 426 | if (err) | 427 | if (err) |
| @@ -464,15 +465,15 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 464 | */ | 465 | */ |
| 465 | static inline void | 466 | static inline void |
| 466 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 467 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 467 | struct pt_regs * regs, struct switch_stack *sw) | 468 | struct pt_regs * regs) |
| 468 | { | 469 | { |
| 469 | sigset_t *oldset = sigmask_to_save(); | 470 | sigset_t *oldset = sigmask_to_save(); |
| 470 | int ret; | 471 | int ret; |
| 471 | 472 | ||
| 472 | if (ka->sa.sa_flags & SA_SIGINFO) | 473 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 473 | ret = setup_rt_frame(sig, ka, info, oldset, regs, sw); | 474 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
| 474 | else | 475 | else |
| 475 | ret = setup_frame(sig, ka, oldset, regs, sw); | 476 | ret = setup_frame(sig, ka, oldset, regs); |
| 476 | 477 | ||
| 477 | if (ret) { | 478 | if (ret) { |
| 478 | force_sigsegv(sig, current); | 479 | force_sigsegv(sig, current); |
| @@ -519,8 +520,7 @@ syscall_restart(unsigned long r0, unsigned long r19, | |||
| 519 | * all (if we get here from anything but a syscall return, it will be 0) | 520 | * all (if we get here from anything but a syscall return, it will be 0) |
| 520 | */ | 521 | */ |
| 521 | static void | 522 | static void |
| 522 | do_signal(struct pt_regs * regs, struct switch_stack * sw, | 523 | do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19) |
| 523 | unsigned long r0, unsigned long r19) | ||
| 524 | { | 524 | { |
| 525 | siginfo_t info; | 525 | siginfo_t info; |
| 526 | int signr; | 526 | int signr; |
| @@ -537,7 +537,7 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, | |||
| 537 | /* Whee! Actually deliver the signal. */ | 537 | /* Whee! Actually deliver the signal. */ |
| 538 | if (r0) | 538 | if (r0) |
| 539 | syscall_restart(r0, r19, regs, &ka); | 539 | syscall_restart(r0, r19, regs, &ka); |
| 540 | handle_signal(signr, &ka, &info, regs, sw); | 540 | handle_signal(signr, &ka, &info, regs); |
| 541 | if (single_stepping) | 541 | if (single_stepping) |
| 542 | ptrace_set_bpt(current); /* re-set bpt */ | 542 | ptrace_set_bpt(current); /* re-set bpt */ |
| 543 | return; | 543 | return; |
| @@ -568,15 +568,23 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, | |||
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | void | 570 | void |
| 571 | do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, | 571 | do_work_pending(struct pt_regs *regs, unsigned long thread_flags, |
| 572 | unsigned long thread_info_flags, | ||
| 573 | unsigned long r0, unsigned long r19) | 572 | unsigned long r0, unsigned long r19) |
| 574 | { | 573 | { |
| 575 | if (thread_info_flags & _TIF_SIGPENDING) | 574 | do { |
| 576 | do_signal(regs, sw, r0, r19); | 575 | if (thread_flags & _TIF_NEED_RESCHED) { |
| 577 | 576 | schedule(); | |
| 578 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 577 | } else { |
| 579 | clear_thread_flag(TIF_NOTIFY_RESUME); | 578 | local_irq_enable(); |
| 580 | tracehook_notify_resume(regs); | 579 | if (thread_flags & _TIF_SIGPENDING) { |
| 581 | } | 580 | do_signal(regs, r0, r19); |
| 581 | r0 = 0; | ||
| 582 | } else { | ||
| 583 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 584 | tracehook_notify_resume(regs); | ||
| 585 | } | ||
| 586 | } | ||
| 587 | local_irq_disable(); | ||
| 588 | thread_flags = current_thread_info()->flags; | ||
| 589 | } while (thread_flags & _TIF_WORK_MASK); | ||
| 582 | } | 590 | } |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 767aae8277fa..431c3753145a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -53,6 +53,7 @@ config ARM | |||
| 53 | select GENERIC_STRNLEN_USER | 53 | select GENERIC_STRNLEN_USER |
| 54 | select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN | 54 | select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN |
| 55 | select GENERIC_KERNEL_THREAD | 55 | select GENERIC_KERNEL_THREAD |
| 56 | select GENERIC_KERNEL_EXECVE | ||
| 56 | help | 57 | help |
| 57 | The ARM series is a line of low-power-consumption RISC chip designs | 58 | The ARM series is a line of low-power-consumption RISC chip designs |
| 58 | licensed by ARM Ltd and targeted at embedded applications and | 59 | licensed by ARM Ltd and targeted at embedded applications and |
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index f259921edfe9..91819ad54424 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h | |||
| @@ -479,7 +479,6 @@ | |||
| 479 | #define __ARCH_WANT_SYS_SOCKETCALL | 479 | #define __ARCH_WANT_SYS_SOCKETCALL |
| 480 | #endif | 480 | #endif |
| 481 | #define __ARCH_WANT_SYS_EXECVE | 481 | #define __ARCH_WANT_SYS_EXECVE |
| 482 | #define __ARCH_WANT_KERNEL_EXECVE | ||
| 483 | 482 | ||
| 484 | /* | 483 | /* |
| 485 | * "Conditional" syscalls | 484 | * "Conditional" syscalls |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index e340fa1db203..417bac1846bd 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
| @@ -86,35 +86,14 @@ ENDPROC(ret_to_user) | |||
| 86 | */ | 86 | */ |
| 87 | ENTRY(ret_from_fork) | 87 | ENTRY(ret_from_fork) |
| 88 | bl schedule_tail | 88 | bl schedule_tail |
| 89 | cmp r5, #0 | ||
| 90 | movne r0, r4 | ||
| 91 | movne lr, pc | ||
| 92 | movne pc, r5 | ||
| 89 | get_thread_info tsk | 93 | get_thread_info tsk |
| 90 | mov why, #1 | ||
| 91 | b ret_slow_syscall | 94 | b ret_slow_syscall |
| 92 | ENDPROC(ret_from_fork) | 95 | ENDPROC(ret_from_fork) |
| 93 | 96 | ||
| 94 | ENTRY(ret_from_kernel_thread) | ||
| 95 | UNWIND(.fnstart) | ||
| 96 | UNWIND(.cantunwind) | ||
| 97 | bl schedule_tail | ||
| 98 | mov r0, r4 | ||
| 99 | adr lr, BSYM(1f) @ kernel threads should not exit | ||
| 100 | mov pc, r5 | ||
| 101 | 1: bl do_exit | ||
| 102 | nop | ||
| 103 | UNWIND(.fnend) | ||
| 104 | ENDPROC(ret_from_kernel_thread) | ||
| 105 | |||
| 106 | /* | ||
| 107 | * turn a kernel thread into userland process | ||
| 108 | * use: ret_from_kernel_execve(struct pt_regs *normal) | ||
| 109 | */ | ||
| 110 | ENTRY(ret_from_kernel_execve) | ||
| 111 | mov why, #0 @ not a syscall | ||
| 112 | str why, [r0, #S_R0] @ ... and we want 0 in ->ARM_r0 as well | ||
| 113 | get_thread_info tsk @ thread structure | ||
| 114 | mov sp, r0 @ stack pointer just under pt_regs | ||
| 115 | b ret_slow_syscall | ||
| 116 | ENDPROC(ret_from_kernel_execve) | ||
| 117 | |||
| 118 | .equ NR_syscalls,0 | 97 | .equ NR_syscalls,0 |
| 119 | #define CALL(x) .equ NR_syscalls,NR_syscalls+1 | 98 | #define CALL(x) .equ NR_syscalls,NR_syscalls+1 |
| 120 | #include "calls.S" | 99 | #include "calls.S" |
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index f98c17ff1957..90084a6de35a 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
| @@ -373,7 +373,6 @@ void release_thread(struct task_struct *dead_task) | |||
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 375 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
| 376 | asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); | ||
| 377 | 376 | ||
| 378 | int | 377 | int |
| 379 | copy_thread(unsigned long clone_flags, unsigned long stack_start, | 378 | copy_thread(unsigned long clone_flags, unsigned long stack_start, |
| @@ -388,13 +387,13 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start, | |||
| 388 | *childregs = *regs; | 387 | *childregs = *regs; |
| 389 | childregs->ARM_r0 = 0; | 388 | childregs->ARM_r0 = 0; |
| 390 | childregs->ARM_sp = stack_start; | 389 | childregs->ARM_sp = stack_start; |
| 391 | thread->cpu_context.pc = (unsigned long)ret_from_fork; | ||
| 392 | } else { | 390 | } else { |
| 391 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
| 393 | thread->cpu_context.r4 = stk_sz; | 392 | thread->cpu_context.r4 = stk_sz; |
| 394 | thread->cpu_context.r5 = stack_start; | 393 | thread->cpu_context.r5 = stack_start; |
| 395 | thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread; | ||
| 396 | childregs->ARM_cpsr = SVC_MODE; | 394 | childregs->ARM_cpsr = SVC_MODE; |
| 397 | } | 395 | } |
| 396 | thread->cpu_context.pc = (unsigned long)ret_from_fork; | ||
| 398 | thread->cpu_context.sp = (unsigned long)childregs; | 397 | thread->cpu_context.sp = (unsigned long)childregs; |
| 399 | 398 | ||
| 400 | clear_ptrace_hw_breakpoint(p); | 399 | clear_ptrace_hw_breakpoint(p); |
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 51faaac8abe6..185bedd926df 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
| 26 | #include <linux/kthread.h> | ||
| 26 | #include <asm/eeh_event.h> | 27 | #include <asm/eeh_event.h> |
| 27 | #include <asm/ppc-pci.h> | 28 | #include <asm/ppc-pci.h> |
| 28 | 29 | ||
| @@ -59,8 +60,6 @@ static int eeh_event_handler(void * dummy) | |||
| 59 | struct eeh_event *event; | 60 | struct eeh_event *event; |
| 60 | struct eeh_pe *pe; | 61 | struct eeh_pe *pe; |
| 61 | 62 | ||
| 62 | set_task_comm(current, "eehd"); | ||
| 63 | |||
| 64 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | 63 | spin_lock_irqsave(&eeh_eventlist_lock, flags); |
| 65 | event = NULL; | 64 | event = NULL; |
| 66 | 65 | ||
| @@ -108,7 +107,7 @@ static int eeh_event_handler(void * dummy) | |||
| 108 | */ | 107 | */ |
| 109 | static void eeh_thread_launcher(struct work_struct *dummy) | 108 | static void eeh_thread_launcher(struct work_struct *dummy) |
| 110 | { | 109 | { |
| 111 | if (kernel_thread(eeh_event_handler, NULL, CLONE_KERNEL) < 0) | 110 | if (IS_ERR(kthread_run(eeh_event_handler, NULL, "eehd"))) |
| 112 | printk(KERN_ERR "Failed to start EEH daemon\n"); | 111 | printk(KERN_ERR "Failed to start EEH daemon\n"); |
| 113 | } | 112 | } |
| 114 | 113 | ||
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index 1e82e954e978..c03cd5a02364 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h | |||
| @@ -26,7 +26,6 @@ struct thread_struct { | |||
| 26 | jmp_buf *fault_catcher; | 26 | jmp_buf *fault_catcher; |
| 27 | struct task_struct *prev_sched; | 27 | struct task_struct *prev_sched; |
| 28 | unsigned long temp_stack; | 28 | unsigned long temp_stack; |
| 29 | jmp_buf *exec_buf; | ||
| 30 | struct arch_thread arch; | 29 | struct arch_thread arch; |
| 31 | jmp_buf switch_buf; | 30 | jmp_buf switch_buf; |
| 32 | int mm_count; | 31 | int mm_count; |
| @@ -54,7 +53,6 @@ struct thread_struct { | |||
| 54 | .fault_addr = NULL, \ | 53 | .fault_addr = NULL, \ |
| 55 | .prev_sched = NULL, \ | 54 | .prev_sched = NULL, \ |
| 56 | .temp_stack = 0, \ | 55 | .temp_stack = 0, \ |
| 57 | .exec_buf = NULL, \ | ||
| 58 | .arch = INIT_ARCH_THREAD, \ | 56 | .arch = INIT_ARCH_THREAD, \ |
| 59 | .request = { 0 } \ | 57 | .request = { 0 } \ |
| 60 | } | 58 | } |
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 44883049c11d..95feaa47a2fb 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h | |||
| @@ -191,7 +191,6 @@ extern int os_getpid(void); | |||
| 191 | extern int os_getpgrp(void); | 191 | extern int os_getpgrp(void); |
| 192 | 192 | ||
| 193 | extern void init_new_thread_signals(void); | 193 | extern void init_new_thread_signals(void); |
| 194 | extern int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr); | ||
| 195 | 194 | ||
| 196 | extern int os_map_memory(void *virt, int fd, unsigned long long off, | 195 | extern int os_map_memory(void *virt, int fd, unsigned long long off, |
| 197 | unsigned long len, int r, int w, int x); | 196 | unsigned long len, int r, int w, int x); |
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index ab019c7f0b57..3a8ece7d09ca 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c | |||
| @@ -47,8 +47,3 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) | |||
| 47 | #endif | 47 | #endif |
| 48 | } | 48 | } |
| 49 | EXPORT_SYMBOL(start_thread); | 49 | EXPORT_SYMBOL(start_thread); |
| 50 | |||
| 51 | void __noreturn ret_from_kernel_execve(struct pt_regs *unused) | ||
| 52 | { | ||
| 53 | UML_LONGJMP(current->thread.exec_buf, 1); | ||
| 54 | } | ||
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 30629783b3e0..b6d699cdd557 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c | |||
| @@ -135,14 +135,10 @@ void new_thread_handler(void) | |||
| 135 | arg = current->thread.request.u.thread.arg; | 135 | arg = current->thread.request.u.thread.arg; |
| 136 | 136 | ||
| 137 | /* | 137 | /* |
| 138 | * The return value is 1 if the kernel thread execs a process, | 138 | * callback returns only if the kernel thread execs a process |
| 139 | * 0 if it just exits | ||
| 140 | */ | 139 | */ |
| 141 | n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); | 140 | n = fn(arg); |
| 142 | if (n == 1) | 141 | userspace(¤t->thread.regs.regs); |
| 143 | userspace(¤t->thread.regs.regs); | ||
| 144 | else | ||
| 145 | do_exit(0); | ||
| 146 | } | 142 | } |
| 147 | 143 | ||
| 148 | /* Called magically, see new_thread_handler above */ | 144 | /* Called magically, see new_thread_handler above */ |
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 162bea3d91b2..b8f34c9e53ae 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c | |||
| @@ -244,16 +244,3 @@ void init_new_thread_signals(void) | |||
| 244 | signal(SIGWINCH, SIG_IGN); | 244 | signal(SIGWINCH, SIG_IGN); |
| 245 | signal(SIGTERM, SIG_DFL); | 245 | signal(SIGTERM, SIG_DFL); |
| 246 | } | 246 | } |
| 247 | |||
| 248 | int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr) | ||
| 249 | { | ||
| 250 | jmp_buf buf; | ||
| 251 | int n; | ||
| 252 | |||
| 253 | *jmp_ptr = &buf; | ||
| 254 | n = UML_SETJMP(&buf); | ||
| 255 | if (n != 0) | ||
| 256 | return n; | ||
| 257 | (*fn)(arg); | ||
| 258 | return 0; | ||
| 259 | } | ||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 42d2c35a5bbd..70071b19eb98 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -109,6 +109,7 @@ config X86 | |||
| 109 | select HAVE_RCU_USER_QS if X86_64 | 109 | select HAVE_RCU_USER_QS if X86_64 |
| 110 | select HAVE_IRQ_TIME_ACCOUNTING | 110 | select HAVE_IRQ_TIME_ACCOUNTING |
| 111 | select GENERIC_KERNEL_THREAD | 111 | select GENERIC_KERNEL_THREAD |
| 112 | select GENERIC_KERNEL_EXECVE | ||
| 112 | 113 | ||
| 113 | config INSTRUCTION_DECODER | 114 | config INSTRUCTION_DECODER |
| 114 | def_bool y | 115 | def_bool y |
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 55d155560fdf..16f3fc6ebf2e 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h | |||
| @@ -51,7 +51,6 @@ | |||
| 51 | # define __ARCH_WANT_SYS_UTIME | 51 | # define __ARCH_WANT_SYS_UTIME |
| 52 | # define __ARCH_WANT_SYS_WAITPID | 52 | # define __ARCH_WANT_SYS_WAITPID |
| 53 | # define __ARCH_WANT_SYS_EXECVE | 53 | # define __ARCH_WANT_SYS_EXECVE |
| 54 | # define __ARCH_WANT_KERNEL_EXECVE | ||
| 55 | 54 | ||
| 56 | /* | 55 | /* |
| 57 | * "Conditional" syscalls | 56 | * "Conditional" syscalls |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 2c6340796fe9..a1193aef6d7d 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
| @@ -299,12 +299,20 @@ ENTRY(ret_from_fork) | |||
| 299 | CFI_ENDPROC | 299 | CFI_ENDPROC |
| 300 | END(ret_from_fork) | 300 | END(ret_from_fork) |
| 301 | 301 | ||
| 302 | ENTRY(ret_from_kernel_execve) | 302 | ENTRY(ret_from_kernel_thread) |
| 303 | movl %eax, %esp | 303 | CFI_STARTPROC |
| 304 | movl $0,PT_EAX(%esp) | 304 | pushl_cfi %eax |
| 305 | call schedule_tail | ||
| 305 | GET_THREAD_INFO(%ebp) | 306 | GET_THREAD_INFO(%ebp) |
| 307 | popl_cfi %eax | ||
| 308 | pushl_cfi $0x0202 # Reset kernel eflags | ||
| 309 | popfl_cfi | ||
| 310 | movl PT_EBP(%esp),%eax | ||
| 311 | call *PT_EBX(%esp) | ||
| 312 | movl $0,PT_EAX(%esp) | ||
| 306 | jmp syscall_exit | 313 | jmp syscall_exit |
| 307 | END(ret_from_kernel_execve) | 314 | CFI_ENDPROC |
| 315 | ENDPROC(ret_from_kernel_thread) | ||
| 308 | 316 | ||
| 309 | /* | 317 | /* |
| 310 | * Interrupt exit functions should be protected against kprobes | 318 | * Interrupt exit functions should be protected against kprobes |
| @@ -1015,21 +1023,6 @@ END(spurious_interrupt_bug) | |||
| 1015 | */ | 1023 | */ |
| 1016 | .popsection | 1024 | .popsection |
| 1017 | 1025 | ||
| 1018 | ENTRY(ret_from_kernel_thread) | ||
| 1019 | CFI_STARTPROC | ||
| 1020 | pushl_cfi %eax | ||
| 1021 | call schedule_tail | ||
| 1022 | GET_THREAD_INFO(%ebp) | ||
| 1023 | popl_cfi %eax | ||
| 1024 | pushl_cfi $0x0202 # Reset kernel eflags | ||
| 1025 | popfl_cfi | ||
| 1026 | movl PT_EBP(%esp),%eax | ||
| 1027 | call *PT_EBX(%esp) | ||
| 1028 | call do_exit | ||
| 1029 | ud2 # padding for call trace | ||
| 1030 | CFI_ENDPROC | ||
| 1031 | ENDPROC(ret_from_kernel_thread) | ||
| 1032 | |||
| 1033 | #ifdef CONFIG_XEN | 1026 | #ifdef CONFIG_XEN |
| 1034 | /* Xen doesn't set %esp to be precisely what the normal sysenter | 1027 | /* Xen doesn't set %esp to be precisely what the normal sysenter |
| 1035 | entrypoint expects, so fix it up before using the normal path. */ | 1028 | entrypoint expects, so fix it up before using the normal path. */ |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index cdc790c78f32..0c58952d64e8 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
| @@ -563,15 +563,13 @@ ENTRY(ret_from_fork) | |||
| 563 | jmp ret_from_sys_call # go to the SYSRET fastpath | 563 | jmp ret_from_sys_call # go to the SYSRET fastpath |
| 564 | 564 | ||
| 565 | 1: | 565 | 1: |
| 566 | subq $REST_SKIP, %rsp # move the stack pointer back | 566 | subq $REST_SKIP, %rsp # leave space for volatiles |
| 567 | CFI_ADJUST_CFA_OFFSET REST_SKIP | 567 | CFI_ADJUST_CFA_OFFSET REST_SKIP |
| 568 | movq %rbp, %rdi | 568 | movq %rbp, %rdi |
| 569 | call *%rbx | 569 | call *%rbx |
| 570 | # exit | 570 | movl $0, RAX(%rsp) |
| 571 | mov %eax, %edi | 571 | RESTORE_REST |
| 572 | call do_exit | 572 | jmp int_ret_from_sys_call |
| 573 | ud2 # padding for call trace | ||
| 574 | |||
| 575 | CFI_ENDPROC | 573 | CFI_ENDPROC |
| 576 | END(ret_from_fork) | 574 | END(ret_from_fork) |
| 577 | 575 | ||
| @@ -1326,20 +1324,6 @@ bad_gs: | |||
| 1326 | jmp 2b | 1324 | jmp 2b |
| 1327 | .previous | 1325 | .previous |
| 1328 | 1326 | ||
| 1329 | ENTRY(ret_from_kernel_execve) | ||
| 1330 | movq %rdi, %rsp | ||
| 1331 | movl $0, RAX(%rsp) | ||
| 1332 | // RESTORE_REST | ||
| 1333 | movq 0*8(%rsp), %r15 | ||
| 1334 | movq 1*8(%rsp), %r14 | ||
| 1335 | movq 2*8(%rsp), %r13 | ||
| 1336 | movq 3*8(%rsp), %r12 | ||
| 1337 | movq 4*8(%rsp), %rbp | ||
| 1338 | movq 5*8(%rsp), %rbx | ||
| 1339 | addq $(6*8), %rsp | ||
| 1340 | jmp int_ret_from_sys_call | ||
| 1341 | END(ret_from_kernel_execve) | ||
| 1342 | |||
| 1343 | /* Call softirq on interrupt stack. Interrupts are off. */ | 1327 | /* Call softirq on interrupt stack. Interrupts are off. */ |
| 1344 | ENTRY(call_softirq) | 1328 | ENTRY(call_softirq) |
| 1345 | CFI_STARTPROC | 1329 | CFI_STARTPROC |
diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig index 30c4eec033af..9fa950df80e5 100644 --- a/arch/x86/um/Kconfig +++ b/arch/x86/um/Kconfig | |||
| @@ -14,6 +14,7 @@ config UML_X86 | |||
| 14 | def_bool y | 14 | def_bool y |
| 15 | select GENERIC_FIND_FIRST_BIT | 15 | select GENERIC_FIND_FIRST_BIT |
| 16 | select GENERIC_KERNEL_THREAD | 16 | select GENERIC_KERNEL_THREAD |
| 17 | select GENERIC_KERNEL_EXECVE | ||
| 17 | 18 | ||
| 18 | config 64BIT | 19 | config 64BIT |
| 19 | bool "64-bit kernel" if SUBARCH = "x86" | 20 | bool "64-bit kernel" if SUBARCH = "x86" |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 19439c75c5b2..727f0cd73921 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
| @@ -827,7 +827,15 @@ asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags, | |||
| 827 | const char __user *pathname); | 827 | const char __user *pathname); |
| 828 | asmlinkage long sys_syncfs(int fd); | 828 | asmlinkage long sys_syncfs(int fd); |
| 829 | 829 | ||
| 830 | #ifndef CONFIG_GENERIC_KERNEL_EXECVE | ||
| 830 | int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]); | 831 | int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]); |
| 832 | #else | ||
| 833 | #define kernel_execve(filename, argv, envp) \ | ||
| 834 | do_execve(filename, \ | ||
| 835 | (const char __user *const __user *)argv, \ | ||
| 836 | (const char __user *const __user *)envp, \ | ||
| 837 | current_pt_regs()) | ||
| 838 | #endif | ||
| 831 | 839 | ||
| 832 | 840 | ||
| 833 | asmlinkage long sys_perf_event_open( | 841 | asmlinkage long sys_perf_event_open( |
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 135959a276be..5e4ded51788e 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c | |||
| @@ -16,13 +16,13 @@ | |||
| 16 | #include <linux/initrd.h> | 16 | #include <linux/initrd.h> |
| 17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
| 18 | #include <linux/freezer.h> | 18 | #include <linux/freezer.h> |
| 19 | #include <linux/kmod.h> | ||
| 19 | 20 | ||
| 20 | #include "do_mounts.h" | 21 | #include "do_mounts.h" |
| 21 | 22 | ||
| 22 | unsigned long initrd_start, initrd_end; | 23 | unsigned long initrd_start, initrd_end; |
| 23 | int initrd_below_start_ok; | 24 | int initrd_below_start_ok; |
| 24 | unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ | 25 | unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ |
| 25 | static int __initdata old_fd, root_fd; | ||
| 26 | static int __initdata mount_initrd = 1; | 26 | static int __initdata mount_initrd = 1; |
| 27 | 27 | ||
| 28 | static int __init no_initrd(char *str) | 28 | static int __init no_initrd(char *str) |
| @@ -33,33 +33,29 @@ static int __init no_initrd(char *str) | |||
| 33 | 33 | ||
| 34 | __setup("noinitrd", no_initrd); | 34 | __setup("noinitrd", no_initrd); |
| 35 | 35 | ||
| 36 | static int __init do_linuxrc(void *_shell) | 36 | static int init_linuxrc(struct subprocess_info *info, struct cred *new) |
| 37 | { | 37 | { |
| 38 | static const char *argv[] = { "linuxrc", NULL, }; | 38 | sys_unshare(CLONE_FS | CLONE_FILES); |
| 39 | extern const char *envp_init[]; | 39 | /* move initrd over / and chdir/chroot in initrd root */ |
| 40 | const char *shell = _shell; | 40 | sys_chdir("/root"); |
| 41 | 41 | sys_mount(".", "/", NULL, MS_MOVE, NULL); | |
| 42 | sys_close(old_fd);sys_close(root_fd); | 42 | sys_chroot("."); |
| 43 | sys_setsid(); | 43 | sys_setsid(); |
| 44 | return kernel_execve(shell, argv, envp_init); | 44 | return 0; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | static void __init handle_initrd(void) | 47 | static void __init handle_initrd(void) |
| 48 | { | 48 | { |
| 49 | static char *argv[] = { "linuxrc", NULL, }; | ||
| 50 | extern char *envp_init[]; | ||
| 49 | int error; | 51 | int error; |
| 50 | int pid; | ||
| 51 | 52 | ||
| 52 | real_root_dev = new_encode_dev(ROOT_DEV); | 53 | real_root_dev = new_encode_dev(ROOT_DEV); |
| 53 | create_dev("/dev/root.old", Root_RAM0); | 54 | create_dev("/dev/root.old", Root_RAM0); |
| 54 | /* mount initrd on rootfs' /root */ | 55 | /* mount initrd on rootfs' /root */ |
| 55 | mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); | 56 | mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); |
| 56 | sys_mkdir("/old", 0700); | 57 | sys_mkdir("/old", 0700); |
| 57 | root_fd = sys_open("/", 0, 0); | 58 | sys_chdir("/old"); |
| 58 | old_fd = sys_open("/old", 0, 0); | ||
| 59 | /* move initrd over / and chdir/chroot in initrd root */ | ||
| 60 | sys_chdir("/root"); | ||
| 61 | sys_mount(".", "/", NULL, MS_MOVE, NULL); | ||
| 62 | sys_chroot("."); | ||
| 63 | 59 | ||
| 64 | /* | 60 | /* |
| 65 | * In case that a resume from disk is carried out by linuxrc or one of | 61 | * In case that a resume from disk is carried out by linuxrc or one of |
| @@ -67,27 +63,22 @@ static void __init handle_initrd(void) | |||
| 67 | */ | 63 | */ |
| 68 | current->flags |= PF_FREEZER_SKIP; | 64 | current->flags |= PF_FREEZER_SKIP; |
| 69 | 65 | ||
| 70 | pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); | 66 | call_usermodehelper_fns("/linuxrc", argv, envp_init, UMH_WAIT_PROC, |
| 71 | if (pid > 0) | 67 | init_linuxrc, NULL, NULL); |
| 72 | while (pid != sys_wait4(-1, NULL, 0, NULL)) | ||
| 73 | yield(); | ||
| 74 | 68 | ||
| 75 | current->flags &= ~PF_FREEZER_SKIP; | 69 | current->flags &= ~PF_FREEZER_SKIP; |
| 76 | 70 | ||
| 77 | /* move initrd to rootfs' /old */ | 71 | /* move initrd to rootfs' /old */ |
| 78 | sys_fchdir(old_fd); | 72 | sys_mount("..", ".", NULL, MS_MOVE, NULL); |
| 79 | sys_mount("/", ".", NULL, MS_MOVE, NULL); | ||
| 80 | /* switch root and cwd back to / of rootfs */ | 73 | /* switch root and cwd back to / of rootfs */ |
| 81 | sys_fchdir(root_fd); | 74 | sys_chroot(".."); |
| 82 | sys_chroot("."); | ||
| 83 | sys_close(old_fd); | ||
| 84 | sys_close(root_fd); | ||
| 85 | 75 | ||
| 86 | if (new_decode_dev(real_root_dev) == Root_RAM0) { | 76 | if (new_decode_dev(real_root_dev) == Root_RAM0) { |
| 87 | sys_chdir("/old"); | 77 | sys_chdir("/old"); |
| 88 | return; | 78 | return; |
| 89 | } | 79 | } |
| 90 | 80 | ||
| 81 | sys_chdir("/"); | ||
| 91 | ROOT_DEV = new_decode_dev(real_root_dev); | 82 | ROOT_DEV = new_decode_dev(real_root_dev); |
| 92 | mount_root(); | 83 | mount_root(); |
| 93 | 84 | ||
diff --git a/init/main.c b/init/main.c index 313360fe1118..9cf77ab138a6 100644 --- a/init/main.c +++ b/init/main.c | |||
| @@ -69,6 +69,7 @@ | |||
| 69 | #include <linux/slab.h> | 69 | #include <linux/slab.h> |
| 70 | #include <linux/perf_event.h> | 70 | #include <linux/perf_event.h> |
| 71 | #include <linux/file.h> | 71 | #include <linux/file.h> |
| 72 | #include <linux/ptrace.h> | ||
| 72 | 73 | ||
| 73 | #include <asm/io.h> | 74 | #include <asm/io.h> |
| 74 | #include <asm/bugs.h> | 75 | #include <asm/bugs.h> |
| @@ -791,17 +792,17 @@ static void __init do_pre_smp_initcalls(void) | |||
| 791 | do_one_initcall(*fn); | 792 | do_one_initcall(*fn); |
| 792 | } | 793 | } |
| 793 | 794 | ||
| 794 | static void run_init_process(const char *init_filename) | 795 | static int run_init_process(const char *init_filename) |
| 795 | { | 796 | { |
| 796 | argv_init[0] = init_filename; | 797 | argv_init[0] = init_filename; |
| 797 | kernel_execve(init_filename, argv_init, envp_init); | 798 | return kernel_execve(init_filename, argv_init, envp_init); |
| 798 | } | 799 | } |
| 799 | 800 | ||
| 800 | /* This is a non __init function. Force it to be noinline otherwise gcc | 801 | static void __init kernel_init_freeable(void); |
| 801 | * makes it inline to init() and it becomes part of init.text section | 802 | |
| 802 | */ | 803 | static int __ref kernel_init(void *unused) |
| 803 | static noinline int init_post(void) | ||
| 804 | { | 804 | { |
| 805 | kernel_init_freeable(); | ||
| 805 | /* need to finish all async __init code before freeing the memory */ | 806 | /* need to finish all async __init code before freeing the memory */ |
| 806 | async_synchronize_full(); | 807 | async_synchronize_full(); |
| 807 | free_initmem(); | 808 | free_initmem(); |
| @@ -813,7 +814,8 @@ static noinline int init_post(void) | |||
| 813 | flush_delayed_fput(); | 814 | flush_delayed_fput(); |
| 814 | 815 | ||
| 815 | if (ramdisk_execute_command) { | 816 | if (ramdisk_execute_command) { |
| 816 | run_init_process(ramdisk_execute_command); | 817 | if (!run_init_process(ramdisk_execute_command)) |
| 818 | return 0; | ||
| 817 | printk(KERN_WARNING "Failed to execute %s\n", | 819 | printk(KERN_WARNING "Failed to execute %s\n", |
| 818 | ramdisk_execute_command); | 820 | ramdisk_execute_command); |
| 819 | } | 821 | } |
| @@ -825,20 +827,22 @@ static noinline int init_post(void) | |||
| 825 | * trying to recover a really broken machine. | 827 | * trying to recover a really broken machine. |
| 826 | */ | 828 | */ |
| 827 | if (execute_command) { | 829 | if (execute_command) { |
| 828 | run_init_process(execute_command); | 830 | if (!run_init_process(execute_command)) |
| 831 | return 0; | ||
| 829 | printk(KERN_WARNING "Failed to execute %s. Attempting " | 832 | printk(KERN_WARNING "Failed to execute %s. Attempting " |
| 830 | "defaults...\n", execute_command); | 833 | "defaults...\n", execute_command); |
| 831 | } | 834 | } |
| 832 | run_init_process("/sbin/init"); | 835 | if (!run_init_process("/sbin/init") || |
| 833 | run_init_process("/etc/init"); | 836 | !run_init_process("/etc/init") || |
| 834 | run_init_process("/bin/init"); | 837 | !run_init_process("/bin/init") || |
| 835 | run_init_process("/bin/sh"); | 838 | !run_init_process("/bin/sh")) |
| 839 | return 0; | ||
| 836 | 840 | ||
| 837 | panic("No init found. Try passing init= option to kernel. " | 841 | panic("No init found. Try passing init= option to kernel. " |
| 838 | "See Linux Documentation/init.txt for guidance."); | 842 | "See Linux Documentation/init.txt for guidance."); |
| 839 | } | 843 | } |
| 840 | 844 | ||
| 841 | static int __init kernel_init(void * unused) | 845 | static void __init kernel_init_freeable(void) |
| 842 | { | 846 | { |
| 843 | /* | 847 | /* |
| 844 | * Wait until kthreadd is all set-up. | 848 | * Wait until kthreadd is all set-up. |
| @@ -893,7 +897,4 @@ static int __init kernel_init(void * unused) | |||
| 893 | * we're essentially up and running. Get rid of the | 897 | * we're essentially up and running. Get rid of the |
| 894 | * initmem segments and start the user-mode stuff.. | 898 | * initmem segments and start the user-mode stuff.. |
| 895 | */ | 899 | */ |
| 896 | |||
| 897 | init_post(); | ||
| 898 | return 0; | ||
| 899 | } | 900 | } |
diff --git a/kernel/kmod.c b/kernel/kmod.c index 6f99aead66c6..1c317e386831 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/notifier.h> | 37 | #include <linux/notifier.h> |
| 38 | #include <linux/suspend.h> | 38 | #include <linux/suspend.h> |
| 39 | #include <linux/rwsem.h> | 39 | #include <linux/rwsem.h> |
| 40 | #include <linux/ptrace.h> | ||
| 40 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
| 41 | 42 | ||
| 42 | #include <trace/events/module.h> | 43 | #include <trace/events/module.h> |
| @@ -221,11 +222,13 @@ static int ____call_usermodehelper(void *data) | |||
| 221 | retval = kernel_execve(sub_info->path, | 222 | retval = kernel_execve(sub_info->path, |
| 222 | (const char *const *)sub_info->argv, | 223 | (const char *const *)sub_info->argv, |
| 223 | (const char *const *)sub_info->envp); | 224 | (const char *const *)sub_info->envp); |
| 225 | if (!retval) | ||
| 226 | return 0; | ||
| 224 | 227 | ||
| 225 | /* Exec failed? */ | 228 | /* Exec failed? */ |
| 226 | fail: | 229 | fail: |
| 227 | sub_info->retval = retval; | 230 | sub_info->retval = retval; |
| 228 | return 0; | 231 | do_exit(0); |
| 229 | } | 232 | } |
| 230 | 233 | ||
| 231 | static int call_helper(void *data) | 234 | static int call_helper(void *data) |
| @@ -292,7 +295,7 @@ static int wait_for_helper(void *data) | |||
| 292 | } | 295 | } |
| 293 | 296 | ||
| 294 | umh_complete(sub_info); | 297 | umh_complete(sub_info); |
| 295 | return 0; | 298 | do_exit(0); |
| 296 | } | 299 | } |
| 297 | 300 | ||
| 298 | /* This is run by khelper thread */ | 301 | /* This is run by khelper thread */ |
diff --git a/kernel/kthread.c b/kernel/kthread.c index 146a6fa96825..29fb60caecb5 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/freezer.h> | 18 | #include <linux/freezer.h> |
| 19 | #include <linux/ptrace.h> | ||
| 19 | #include <trace/events/sched.h> | 20 | #include <trace/events/sched.h> |
| 20 | 21 | ||
| 21 | static DEFINE_SPINLOCK(kthread_create_lock); | 22 | static DEFINE_SPINLOCK(kthread_create_lock); |
