diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-07-25 05:37:07 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-25 05:37:07 -0400 |
commit | 0e2f65ee30eee2db054f7fd73f462c5da33ec963 (patch) | |
tree | 26c61eb7745da0c0d9135e9d12088f570cb8530d /arch/x86/kernel/ptrace.c | |
parent | da7878d75b8520c9ae00d27dfbbce546a7bfdfbb (diff) | |
parent | fb2e405fc1fc8b20d9c78eaa1c7fd5a297efde43 (diff) |
Merge branch 'linus' into x86/pebs
Conflicts:
arch/x86/Kconfig.cpu
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/setup_64.c
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r-- | arch/x86/kernel/ptrace.c | 155 |
1 files changed, 58 insertions, 97 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 170f0932f70f..ba19bb49bd09 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -1037,13 +1037,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1037 | return copy_regset_to_user(child, &user_x86_32_view, | 1037 | return copy_regset_to_user(child, &user_x86_32_view, |
1038 | REGSET_XFP, | 1038 | REGSET_XFP, |
1039 | 0, sizeof(struct user_fxsr_struct), | 1039 | 0, sizeof(struct user_fxsr_struct), |
1040 | datap); | 1040 | datap) ? -EIO : 0; |
1041 | 1041 | ||
1042 | case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */ | 1042 | case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */ |
1043 | return copy_regset_from_user(child, &user_x86_32_view, | 1043 | return copy_regset_from_user(child, &user_x86_32_view, |
1044 | REGSET_XFP, | 1044 | REGSET_XFP, |
1045 | 0, sizeof(struct user_fxsr_struct), | 1045 | 0, sizeof(struct user_fxsr_struct), |
1046 | datap); | 1046 | datap) ? -EIO : 0; |
1047 | #endif | 1047 | #endif |
1048 | 1048 | ||
1049 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION | 1049 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION |
@@ -1451,8 +1451,6 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) | |||
1451 | #endif | 1451 | #endif |
1452 | } | 1452 | } |
1453 | 1453 | ||
1454 | #ifdef CONFIG_X86_32 | ||
1455 | |||
1456 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) | 1454 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) |
1457 | { | 1455 | { |
1458 | struct siginfo info; | 1456 | struct siginfo info; |
@@ -1471,89 +1469,10 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) | |||
1471 | force_sig_info(SIGTRAP, &info, tsk); | 1469 | force_sig_info(SIGTRAP, &info, tsk); |
1472 | } | 1470 | } |
1473 | 1471 | ||
1474 | /* notification of system call entry/exit | ||
1475 | * - triggered by current->work.syscall_trace | ||
1476 | */ | ||
1477 | int do_syscall_trace(struct pt_regs *regs, int entryexit) | ||
1478 | { | ||
1479 | int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU); | ||
1480 | /* | ||
1481 | * With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall | ||
1482 | * interception | ||
1483 | */ | ||
1484 | int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP); | ||
1485 | int ret = 0; | ||
1486 | |||
1487 | /* do the secure computing check first */ | ||
1488 | if (!entryexit) | ||
1489 | secure_computing(regs->orig_ax); | ||
1490 | |||
1491 | if (unlikely(current->audit_context)) { | ||
1492 | if (entryexit) | ||
1493 | audit_syscall_exit(AUDITSC_RESULT(regs->ax), | ||
1494 | regs->ax); | ||
1495 | /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only | ||
1496 | * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is | ||
1497 | * not used, entry.S will call us only on syscall exit, not | ||
1498 | * entry; so when TIF_SYSCALL_AUDIT is used we must avoid | ||
1499 | * calling send_sigtrap() on syscall entry. | ||
1500 | * | ||
1501 | * Note that when PTRACE_SYSEMU_SINGLESTEP is used, | ||
1502 | * is_singlestep is false, despite his name, so we will still do | ||
1503 | * the correct thing. | ||
1504 | */ | ||
1505 | else if (is_singlestep) | ||
1506 | goto out; | ||
1507 | } | ||
1508 | |||
1509 | if (!(current->ptrace & PT_PTRACED)) | ||
1510 | goto out; | ||
1511 | |||
1512 | /* If a process stops on the 1st tracepoint with SYSCALL_TRACE | ||
1513 | * and then is resumed with SYSEMU_SINGLESTEP, it will come in | ||
1514 | * here. We have to check this and return */ | ||
1515 | if (is_sysemu && entryexit) | ||
1516 | return 0; | ||
1517 | |||
1518 | /* Fake a debug trap */ | ||
1519 | if (is_singlestep) | ||
1520 | send_sigtrap(current, regs, 0); | ||
1521 | |||
1522 | if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu) | ||
1523 | goto out; | ||
1524 | |||
1525 | /* the 0x80 provides a way for the tracing parent to distinguish | ||
1526 | between a syscall stop and SIGTRAP delivery */ | ||
1527 | /* Note that the debugger could change the result of test_thread_flag!*/ | ||
1528 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80:0)); | ||
1529 | |||
1530 | /* | ||
1531 | * this isn't the same as continuing with a signal, but it will do | ||
1532 | * for normal use. strace only continues with a signal if the | ||
1533 | * stopping signal is not SIGTRAP. -brl | ||
1534 | */ | ||
1535 | if (current->exit_code) { | ||
1536 | send_sig(current->exit_code, current, 1); | ||
1537 | current->exit_code = 0; | ||
1538 | } | ||
1539 | ret = is_sysemu; | ||
1540 | out: | ||
1541 | if (unlikely(current->audit_context) && !entryexit) | ||
1542 | audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_ax, | ||
1543 | regs->bx, regs->cx, regs->dx, regs->si); | ||
1544 | if (ret == 0) | ||
1545 | return 0; | ||
1546 | |||
1547 | regs->orig_ax = -1; /* force skip of syscall restarting */ | ||
1548 | if (unlikely(current->audit_context)) | ||
1549 | audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); | ||
1550 | return 1; | ||
1551 | } | ||
1552 | |||
1553 | #else /* CONFIG_X86_64 */ | ||
1554 | |||
1555 | static void syscall_trace(struct pt_regs *regs) | 1472 | static void syscall_trace(struct pt_regs *regs) |
1556 | { | 1473 | { |
1474 | if (!(current->ptrace & PT_PTRACED)) | ||
1475 | return; | ||
1557 | 1476 | ||
1558 | #if 0 | 1477 | #if 0 |
1559 | printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n", | 1478 | printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n", |
@@ -1575,39 +1494,81 @@ static void syscall_trace(struct pt_regs *regs) | |||
1575 | } | 1494 | } |
1576 | } | 1495 | } |
1577 | 1496 | ||
1578 | asmlinkage void syscall_trace_enter(struct pt_regs *regs) | 1497 | #ifdef CONFIG_X86_32 |
1498 | # define IS_IA32 1 | ||
1499 | #elif defined CONFIG_IA32_EMULATION | ||
1500 | # define IS_IA32 test_thread_flag(TIF_IA32) | ||
1501 | #else | ||
1502 | # define IS_IA32 0 | ||
1503 | #endif | ||
1504 | |||
1505 | /* | ||
1506 | * We must return the syscall number to actually look up in the table. | ||
1507 | * This can be -1L to skip running any syscall at all. | ||
1508 | */ | ||
1509 | asmregparm long syscall_trace_enter(struct pt_regs *regs) | ||
1579 | { | 1510 | { |
1511 | long ret = 0; | ||
1512 | |||
1513 | /* | ||
1514 | * If we stepped into a sysenter/syscall insn, it trapped in | ||
1515 | * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. | ||
1516 | * If user-mode had set TF itself, then it's still clear from | ||
1517 | * do_debug() and we need to set it again to restore the user | ||
1518 | * state. If we entered on the slow path, TF was already set. | ||
1519 | */ | ||
1520 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
1521 | regs->flags |= X86_EFLAGS_TF; | ||
1522 | |||
1580 | /* do the secure computing check first */ | 1523 | /* do the secure computing check first */ |
1581 | secure_computing(regs->orig_ax); | 1524 | secure_computing(regs->orig_ax); |
1582 | 1525 | ||
1583 | if (test_thread_flag(TIF_SYSCALL_TRACE) | 1526 | if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) |
1584 | && (current->ptrace & PT_PTRACED)) | 1527 | ret = -1L; |
1528 | |||
1529 | if (ret || test_thread_flag(TIF_SYSCALL_TRACE)) | ||
1585 | syscall_trace(regs); | 1530 | syscall_trace(regs); |
1586 | 1531 | ||
1587 | if (unlikely(current->audit_context)) { | 1532 | if (unlikely(current->audit_context)) { |
1588 | if (test_thread_flag(TIF_IA32)) { | 1533 | if (IS_IA32) |
1589 | audit_syscall_entry(AUDIT_ARCH_I386, | 1534 | audit_syscall_entry(AUDIT_ARCH_I386, |
1590 | regs->orig_ax, | 1535 | regs->orig_ax, |
1591 | regs->bx, regs->cx, | 1536 | regs->bx, regs->cx, |
1592 | regs->dx, regs->si); | 1537 | regs->dx, regs->si); |
1593 | } else { | 1538 | #ifdef CONFIG_X86_64 |
1539 | else | ||
1594 | audit_syscall_entry(AUDIT_ARCH_X86_64, | 1540 | audit_syscall_entry(AUDIT_ARCH_X86_64, |
1595 | regs->orig_ax, | 1541 | regs->orig_ax, |
1596 | regs->di, regs->si, | 1542 | regs->di, regs->si, |
1597 | regs->dx, regs->r10); | 1543 | regs->dx, regs->r10); |
1598 | } | 1544 | #endif |
1599 | } | 1545 | } |
1546 | |||
1547 | return ret ?: regs->orig_ax; | ||
1600 | } | 1548 | } |
1601 | 1549 | ||
1602 | asmlinkage void syscall_trace_leave(struct pt_regs *regs) | 1550 | asmregparm void syscall_trace_leave(struct pt_regs *regs) |
1603 | { | 1551 | { |
1604 | if (unlikely(current->audit_context)) | 1552 | if (unlikely(current->audit_context)) |
1605 | audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); | 1553 | audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); |
1606 | 1554 | ||
1607 | if ((test_thread_flag(TIF_SYSCALL_TRACE) | 1555 | if (test_thread_flag(TIF_SYSCALL_TRACE)) |
1608 | || test_thread_flag(TIF_SINGLESTEP)) | ||
1609 | && (current->ptrace & PT_PTRACED)) | ||
1610 | syscall_trace(regs); | 1556 | syscall_trace(regs); |
1611 | } | ||
1612 | 1557 | ||
1613 | #endif /* CONFIG_X86_32 */ | 1558 | /* |
1559 | * If TIF_SYSCALL_EMU is set, we only get here because of | ||
1560 | * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). | ||
1561 | * We already reported this syscall instruction in | ||
1562 | * syscall_trace_enter(), so don't do any more now. | ||
1563 | */ | ||
1564 | if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) | ||
1565 | return; | ||
1566 | |||
1567 | /* | ||
1568 | * If we are single-stepping, synthesize a trap to follow the | ||
1569 | * system call instruction. | ||
1570 | */ | ||
1571 | if (test_thread_flag(TIF_SINGLESTEP) && | ||
1572 | (current->ptrace & PT_PTRACED)) | ||
1573 | send_sigtrap(current, regs, 0); | ||
1574 | } | ||