diff options
author | Len Brown <len.brown@intel.com> | 2005-09-08 01:45:47 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2005-09-08 01:45:47 -0400 |
commit | 64e47488c913ac704d465a6af86a26786d1412a5 (patch) | |
tree | d3b0148592963dcde26e4bb35ddfec8b1eaf8e23 /arch/i386/kernel/ptrace.c | |
parent | 4a35a46bf1cda4737c428380d1db5d15e2590d18 (diff) | |
parent | caf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff) |
Merge linux-2.6 with linux-acpi-2.6
Diffstat (limited to 'arch/i386/kernel/ptrace.c')
-rw-r--r-- | arch/i386/kernel/ptrace.c | 63 |
1 files changed, 55 insertions, 8 deletions
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index 0da59b42843c..340980203b09 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c | |||
@@ -271,6 +271,8 @@ static void clear_singlestep(struct task_struct *child) | |||
271 | void ptrace_disable(struct task_struct *child) | 271 | void ptrace_disable(struct task_struct *child) |
272 | { | 272 | { |
273 | clear_singlestep(child); | 273 | clear_singlestep(child); |
274 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
275 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | ||
274 | } | 276 | } |
275 | 277 | ||
276 | /* | 278 | /* |
@@ -509,15 +511,20 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) | |||
509 | } | 511 | } |
510 | break; | 512 | break; |
511 | 513 | ||
514 | case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */ | ||
512 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ | 515 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ |
513 | case PTRACE_CONT: /* restart after signal. */ | 516 | case PTRACE_CONT: /* restart after signal. */ |
514 | ret = -EIO; | 517 | ret = -EIO; |
515 | if (!valid_signal(data)) | 518 | if (!valid_signal(data)) |
516 | break; | 519 | break; |
517 | if (request == PTRACE_SYSCALL) { | 520 | if (request == PTRACE_SYSEMU) { |
521 | set_tsk_thread_flag(child, TIF_SYSCALL_EMU); | ||
522 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
523 | } else if (request == PTRACE_SYSCALL) { | ||
518 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 524 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
519 | } | 525 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); |
520 | else { | 526 | } else { |
527 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | ||
521 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 528 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
522 | } | 529 | } |
523 | child->exit_code = data; | 530 | child->exit_code = data; |
@@ -542,10 +549,17 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) | |||
542 | wake_up_process(child); | 549 | wake_up_process(child); |
543 | break; | 550 | break; |
544 | 551 | ||
552 | case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */ | ||
545 | case PTRACE_SINGLESTEP: /* set the trap flag. */ | 553 | case PTRACE_SINGLESTEP: /* set the trap flag. */ |
546 | ret = -EIO; | 554 | ret = -EIO; |
547 | if (!valid_signal(data)) | 555 | if (!valid_signal(data)) |
548 | break; | 556 | break; |
557 | |||
558 | if (request == PTRACE_SYSEMU_SINGLESTEP) | ||
559 | set_tsk_thread_flag(child, TIF_SYSCALL_EMU); | ||
560 | else | ||
561 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | ||
562 | |||
549 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 563 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
550 | set_singlestep(child); | 564 | set_singlestep(child); |
551 | child->exit_code = data; | 565 | child->exit_code = data; |
@@ -678,26 +692,52 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) | |||
678 | * - triggered by current->work.syscall_trace | 692 | * - triggered by current->work.syscall_trace |
679 | */ | 693 | */ |
680 | __attribute__((regparm(3))) | 694 | __attribute__((regparm(3))) |
681 | void do_syscall_trace(struct pt_regs *regs, int entryexit) | 695 | int do_syscall_trace(struct pt_regs *regs, int entryexit) |
682 | { | 696 | { |
697 | int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU), ret = 0; | ||
698 | /* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall | ||
699 | * interception. */ | ||
700 | int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP); | ||
701 | |||
683 | /* do the secure computing check first */ | 702 | /* do the secure computing check first */ |
684 | secure_computing(regs->orig_eax); | 703 | secure_computing(regs->orig_eax); |
685 | 704 | ||
686 | if (unlikely(current->audit_context) && entryexit) | 705 | if (unlikely(current->audit_context)) { |
687 | audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax); | 706 | if (entryexit) |
707 | audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax); | ||
708 | /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only | ||
709 | * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is | ||
710 | * not used, entry.S will call us only on syscall exit, not | ||
711 | * entry; so when TIF_SYSCALL_AUDIT is used we must avoid | ||
712 | * calling send_sigtrap() on syscall entry. | ||
713 | * | ||
714 | * Note that when PTRACE_SYSEMU_SINGLESTEP is used, | ||
715 | * is_singlestep is false, despite his name, so we will still do | ||
716 | * the correct thing. | ||
717 | */ | ||
718 | else if (is_singlestep) | ||
719 | goto out; | ||
720 | } | ||
688 | 721 | ||
689 | if (!(current->ptrace & PT_PTRACED)) | 722 | if (!(current->ptrace & PT_PTRACED)) |
690 | goto out; | 723 | goto out; |
691 | 724 | ||
725 | /* If a process stops on the 1st tracepoint with SYSCALL_TRACE | ||
726 | * and then is resumed with SYSEMU_SINGLESTEP, it will come in | ||
727 | * here. We have to check this and return */ | ||
728 | if (is_sysemu && entryexit) | ||
729 | return 0; | ||
730 | |||
692 | /* Fake a debug trap */ | 731 | /* Fake a debug trap */ |
693 | if (test_thread_flag(TIF_SINGLESTEP)) | 732 | if (is_singlestep) |
694 | send_sigtrap(current, regs, 0); | 733 | send_sigtrap(current, regs, 0); |
695 | 734 | ||
696 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | 735 | if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu) |
697 | goto out; | 736 | goto out; |
698 | 737 | ||
699 | /* the 0x80 provides a way for the tracing parent to distinguish | 738 | /* the 0x80 provides a way for the tracing parent to distinguish |
700 | between a syscall stop and SIGTRAP delivery */ | 739 | between a syscall stop and SIGTRAP delivery */ |
740 | /* Note that the debugger could change the result of test_thread_flag!*/ | ||
701 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); | 741 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); |
702 | 742 | ||
703 | /* | 743 | /* |
@@ -709,9 +749,16 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit) | |||
709 | send_sig(current->exit_code, current, 1); | 749 | send_sig(current->exit_code, current, 1); |
710 | current->exit_code = 0; | 750 | current->exit_code = 0; |
711 | } | 751 | } |
752 | ret = is_sysemu; | ||
712 | out: | 753 | out: |
713 | if (unlikely(current->audit_context) && !entryexit) | 754 | if (unlikely(current->audit_context) && !entryexit) |
714 | audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax, | 755 | audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax, |
715 | regs->ebx, regs->ecx, regs->edx, regs->esi); | 756 | regs->ebx, regs->ecx, regs->edx, regs->esi); |
757 | if (ret == 0) | ||
758 | return 0; | ||
716 | 759 | ||
760 | regs->orig_eax = -1; /* force skip of syscall restarting */ | ||
761 | if (unlikely(current->audit_context)) | ||
762 | audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax); | ||
763 | return 1; | ||
717 | } | 764 | } |