diff options
-rw-r--r-- | arch/i386/kernel/entry.S | 9 | ||||
-rw-r--r-- | arch/i386/kernel/ptrace.c | 57 | ||||
-rw-r--r-- | include/asm-i386/thread_info.h | 5 | ||||
-rw-r--r-- | include/linux/ptrace.h | 1 | ||||
-rw-r--r-- | kernel/fork.c | 3 |
5 files changed, 53 insertions, 22 deletions
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index a991d4e5edd2..b389e5f3bdee 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S | |||
@@ -203,7 +203,7 @@ sysenter_past_esp: | |||
203 | GET_THREAD_INFO(%ebp) | 203 | GET_THREAD_INFO(%ebp) |
204 | 204 | ||
205 | /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ | 205 | /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ |
206 | testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp) | 206 | testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) |
207 | jnz syscall_trace_entry | 207 | jnz syscall_trace_entry |
208 | cmpl $(nr_syscalls), %eax | 208 | cmpl $(nr_syscalls), %eax |
209 | jae syscall_badsys | 209 | jae syscall_badsys |
@@ -226,9 +226,9 @@ ENTRY(system_call) | |||
226 | pushl %eax # save orig_eax | 226 | pushl %eax # save orig_eax |
227 | SAVE_ALL | 227 | SAVE_ALL |
228 | GET_THREAD_INFO(%ebp) | 228 | GET_THREAD_INFO(%ebp) |
229 | # system call tracing in operation | 229 | # system call tracing in operation / emulation |
230 | /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ | 230 | /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ |
231 | testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp) | 231 | testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) |
232 | jnz syscall_trace_entry | 232 | jnz syscall_trace_entry |
233 | cmpl $(nr_syscalls), %eax | 233 | cmpl $(nr_syscalls), %eax |
234 | jae syscall_badsys | 234 | jae syscall_badsys |
@@ -338,6 +338,9 @@ syscall_trace_entry: | |||
338 | movl %esp, %eax | 338 | movl %esp, %eax |
339 | xorl %edx,%edx | 339 | xorl %edx,%edx |
340 | call do_syscall_trace | 340 | call do_syscall_trace |
341 | cmpl $0, %eax | ||
342 | jne syscall_exit # ret != 0 -> running under PTRACE_SYSEMU, | ||
343 | # so must skip actual syscall | ||
341 | movl ORIG_EAX(%esp), %eax | 344 | movl ORIG_EAX(%esp), %eax |
342 | cmpl $(nr_syscalls), %eax | 345 | cmpl $(nr_syscalls), %eax |
343 | jnae syscall_call | 346 | jnae syscall_call |
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index 5ee9e1d60653..5b569dc1c227 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c | |||
@@ -509,15 +509,27 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) | |||
509 | } | 509 | } |
510 | break; | 510 | break; |
511 | 511 | ||
512 | 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 */ | 513 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ |
513 | case PTRACE_CONT: /* restart after signal. */ | 514 | case PTRACE_CONT: /* restart after signal. */ |
514 | ret = -EIO; | 515 | ret = -EIO; |
515 | if (!valid_signal(data)) | 516 | if (!valid_signal(data)) |
516 | break; | 517 | break; |
518 | /* If we came here with PTRACE_SYSEMU and now continue with | ||
519 | * PTRACE_SYSCALL, entry.S used to intercept the syscall return. | ||
520 | * But it shouldn't! | ||
521 | * So we don't clear TIF_SYSCALL_EMU, which is always unused in | ||
522 | * this special case, to remember, we came from SYSEMU. That | ||
523 | * flag will be cleared by do_syscall_trace(). | ||
524 | */ | ||
525 | if (request == PTRACE_SYSEMU) { | ||
526 | set_tsk_thread_flag(child, TIF_SYSCALL_EMU); | ||
527 | } else if (request == PTRACE_CONT) { | ||
528 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | ||
529 | } | ||
517 | if (request == PTRACE_SYSCALL) { | 530 | if (request == PTRACE_SYSCALL) { |
518 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 531 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
519 | } | 532 | } else { |
520 | else { | ||
521 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 533 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
522 | } | 534 | } |
523 | child->exit_code = data; | 535 | child->exit_code = data; |
@@ -546,6 +558,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) | |||
546 | ret = -EIO; | 558 | ret = -EIO; |
547 | if (!valid_signal(data)) | 559 | if (!valid_signal(data)) |
548 | break; | 560 | break; |
561 | /*See do_syscall_trace to know why we don't clear | ||
562 | * TIF_SYSCALL_EMU.*/ | ||
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,37 +692,43 @@ 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, is_systrace, is_singlestep, ret = 0; | ||
683 | /* do the secure computing check first */ | 698 | /* do the secure computing check first */ |
684 | secure_computing(regs->orig_eax); | 699 | secure_computing(regs->orig_eax); |
685 | 700 | ||
686 | if (unlikely(current->audit_context)) { | 701 | if (unlikely(current->audit_context) && entryexit) |
687 | if (entryexit) | 702 | audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax); |
688 | audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax); | ||
689 | |||
690 | /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only | ||
691 | * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is | ||
692 | * not used, entry.S will call us only on syscall exit, not | ||
693 | * entry ; so when TIF_SYSCALL_AUDIT is used we must avoid | ||
694 | * calling send_sigtrap() on syscall entry. | ||
695 | */ | ||
696 | else if (is_singlestep) | ||
697 | goto out; | ||
698 | } | ||
699 | 703 | ||
700 | if (!(current->ptrace & PT_PTRACED)) | 704 | if (!(current->ptrace & PT_PTRACED)) |
701 | goto out; | 705 | goto out; |
702 | 706 | ||
707 | is_sysemu = test_thread_flag(TIF_SYSCALL_EMU); | ||
708 | is_systrace = test_thread_flag(TIF_SYSCALL_TRACE); | ||
709 | is_singlestep = test_thread_flag(TIF_SINGLESTEP); | ||
710 | |||
711 | /* We can detect the case of coming from PTRACE_SYSEMU and now running | ||
712 | * with PTRACE_SYSCALL or PTRACE_SINGLESTEP, by TIF_SYSCALL_EMU being | ||
713 | * set additionally. | ||
714 | * If so let's reset the flag and return without action (no singlestep | ||
715 | * nor syscall tracing, since no actual step has been executed). | ||
716 | */ | ||
717 | if (is_sysemu && (is_systrace || is_singlestep)) { | ||
718 | clear_thread_flag(TIF_SYSCALL_EMU); | ||
719 | goto out; | ||
720 | } | ||
721 | |||
703 | /* Fake a debug trap */ | 722 | /* Fake a debug trap */ |
704 | if (test_thread_flag(TIF_SINGLESTEP)) | 723 | if (test_thread_flag(TIF_SINGLESTEP)) |
705 | send_sigtrap(current, regs, 0); | 724 | send_sigtrap(current, regs, 0); |
706 | 725 | ||
707 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | 726 | if (!is_systrace && !is_sysemu) |
708 | goto out; | 727 | goto out; |
709 | 728 | ||
710 | /* the 0x80 provides a way for the tracing parent to distinguish | 729 | /* the 0x80 provides a way for the tracing parent to distinguish |
711 | between a syscall stop and SIGTRAP delivery */ | 730 | between a syscall stop and SIGTRAP delivery */ |
731 | /* Note that the debugger could change the result of test_thread_flag!*/ | ||
712 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); | 732 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); |
713 | 733 | ||
714 | /* | 734 | /* |
@@ -720,9 +740,10 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit) | |||
720 | send_sig(current->exit_code, current, 1); | 740 | send_sig(current->exit_code, current, 1); |
721 | current->exit_code = 0; | 741 | current->exit_code = 0; |
722 | } | 742 | } |
743 | ret = is_sysemu; | ||
723 | out: | 744 | out: |
724 | if (unlikely(current->audit_context) && !entryexit) | 745 | if (unlikely(current->audit_context) && !entryexit) |
725 | audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax, | 746 | audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax, |
726 | regs->ebx, regs->ecx, regs->edx, regs->esi); | 747 | regs->ebx, regs->ecx, regs->edx, regs->esi); |
727 | 748 | return ret; | |
728 | } | 749 | } |
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h index 95add81237ea..e2cb9fa6f563 100644 --- a/include/asm-i386/thread_info.h +++ b/include/asm-i386/thread_info.h | |||
@@ -139,6 +139,7 @@ register unsigned long current_stack_pointer asm("esp") __attribute_used__; | |||
139 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ | 139 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ |
140 | #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ | 140 | #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ |
141 | #define TIF_IRET 5 /* return with iret */ | 141 | #define TIF_IRET 5 /* return with iret */ |
142 | #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ | ||
142 | #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ | 143 | #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ |
143 | #define TIF_SECCOMP 8 /* secure computing */ | 144 | #define TIF_SECCOMP 8 /* secure computing */ |
144 | #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ | 145 | #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ |
@@ -150,13 +151,15 @@ register unsigned long current_stack_pointer asm("esp") __attribute_used__; | |||
150 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 151 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
151 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) | 152 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) |
152 | #define _TIF_IRET (1<<TIF_IRET) | 153 | #define _TIF_IRET (1<<TIF_IRET) |
154 | #define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU) | ||
153 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) | 155 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) |
154 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) | 156 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) |
155 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 157 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) |
156 | 158 | ||
157 | /* work to do on interrupt/exception return */ | 159 | /* work to do on interrupt/exception return */ |
158 | #define _TIF_WORK_MASK \ | 160 | #define _TIF_WORK_MASK \ |
159 | (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP)) | 161 | (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\ |
162 | _TIF_SECCOMP|_TIF_SYSCALL_EMU)) | ||
160 | /* work to do on any return to u-space */ | 163 | /* work to do on any return to u-space */ |
161 | #define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP) | 164 | #define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP) |
162 | 165 | ||
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index a373fc254df2..7528afb6b2ad 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #define PTRACE_DETACH 0x11 | 20 | #define PTRACE_DETACH 0x11 |
21 | 21 | ||
22 | #define PTRACE_SYSCALL 24 | 22 | #define PTRACE_SYSCALL 24 |
23 | #define PTRACE_SYSEMU 31 | ||
23 | 24 | ||
24 | /* 0x4200-0x4300 are reserved for architecture-independent additions. */ | 25 | /* 0x4200-0x4300 are reserved for architecture-independent additions. */ |
25 | #define PTRACE_SETOPTIONS 0x4200 | 26 | #define PTRACE_SETOPTIONS 0x4200 |
diff --git a/kernel/fork.c b/kernel/fork.c index b65187f0c74e..7e1ead9a6ba4 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -994,6 +994,9 @@ static task_t *copy_process(unsigned long clone_flags, | |||
994 | * of CLONE_PTRACE. | 994 | * of CLONE_PTRACE. |
995 | */ | 995 | */ |
996 | clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); | 996 | clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); |
997 | #ifdef TIF_SYSCALL_EMU | ||
998 | clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); | ||
999 | #endif | ||
997 | 1000 | ||
998 | /* Our parent execution domain becomes current domain | 1001 | /* Our parent execution domain becomes current domain |
999 | These must match for thread signalling to apply */ | 1002 | These must match for thread signalling to apply */ |