diff options
-rw-r--r-- | arch/x86/include/asm/ptrace.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 157 |
2 files changed, 138 insertions, 24 deletions
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 6205f0c434db..86fc2bb82287 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h | |||
@@ -75,6 +75,11 @@ convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs); | |||
75 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, | 75 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, |
76 | int error_code, int si_code); | 76 | int error_code, int si_code); |
77 | 77 | ||
78 | |||
79 | extern unsigned long syscall_trace_enter_phase1(struct pt_regs *, u32 arch); | ||
80 | extern long syscall_trace_enter_phase2(struct pt_regs *, u32 arch, | ||
81 | unsigned long phase1_result); | ||
82 | |||
78 | extern long syscall_trace_enter(struct pt_regs *); | 83 | extern long syscall_trace_enter(struct pt_regs *); |
79 | extern void syscall_trace_leave(struct pt_regs *); | 84 | extern void syscall_trace_leave(struct pt_regs *); |
80 | 85 | ||
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index bbf338a04a5d..29576c244699 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -1441,20 +1441,126 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, | |||
1441 | force_sig_info(SIGTRAP, &info, tsk); | 1441 | force_sig_info(SIGTRAP, &info, tsk); |
1442 | } | 1442 | } |
1443 | 1443 | ||
1444 | static void do_audit_syscall_entry(struct pt_regs *regs, u32 arch) | ||
1445 | { | ||
1446 | #ifdef CONFIG_X86_64 | ||
1447 | if (arch == AUDIT_ARCH_X86_64) { | ||
1448 | audit_syscall_entry(arch, regs->orig_ax, regs->di, | ||
1449 | regs->si, regs->dx, regs->r10); | ||
1450 | } else | ||
1451 | #endif | ||
1452 | { | ||
1453 | audit_syscall_entry(arch, regs->orig_ax, regs->bx, | ||
1454 | regs->cx, regs->dx, regs->si); | ||
1455 | } | ||
1456 | } | ||
1457 | |||
1444 | /* | 1458 | /* |
1445 | * We must return the syscall number to actually look up in the table. | 1459 | * We can return 0 to resume the syscall or anything else to go to phase |
1446 | * This can be -1L to skip running any syscall at all. | 1460 | * 2. If we resume the syscall, we need to put something appropriate in |
1461 | * regs->orig_ax. | ||
1462 | * | ||
1463 | * NB: We don't have full pt_regs here, but regs->orig_ax and regs->ax | ||
1464 | * are fully functional. | ||
1465 | * | ||
1466 | * For phase 2's benefit, our return value is: | ||
1467 | * 0: resume the syscall | ||
1468 | * 1: go to phase 2; no seccomp phase 2 needed | ||
1469 | * anything else: go to phase 2; pass return value to seccomp | ||
1447 | */ | 1470 | */ |
1448 | long syscall_trace_enter(struct pt_regs *regs) | 1471 | unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch) |
1449 | { | 1472 | { |
1450 | long ret = 0; | 1473 | unsigned long ret = 0; |
1474 | u32 work; | ||
1475 | |||
1476 | BUG_ON(regs != task_pt_regs(current)); | ||
1477 | |||
1478 | work = ACCESS_ONCE(current_thread_info()->flags) & | ||
1479 | _TIF_WORK_SYSCALL_ENTRY; | ||
1451 | 1480 | ||
1452 | /* | 1481 | /* |
1453 | * If TIF_NOHZ is set, we are required to call user_exit() before | 1482 | * If TIF_NOHZ is set, we are required to call user_exit() before |
1454 | * doing anything that could touch RCU. | 1483 | * doing anything that could touch RCU. |
1455 | */ | 1484 | */ |
1456 | if (test_thread_flag(TIF_NOHZ)) | 1485 | if (work & _TIF_NOHZ) { |
1457 | user_exit(); | 1486 | user_exit(); |
1487 | work &= ~TIF_NOHZ; | ||
1488 | } | ||
1489 | |||
1490 | #ifdef CONFIG_SECCOMP | ||
1491 | /* | ||
1492 | * Do seccomp first -- it should minimize exposure of other | ||
1493 | * code, and keeping seccomp fast is probably more valuable | ||
1494 | * than the rest of this. | ||
1495 | */ | ||
1496 | if (work & _TIF_SECCOMP) { | ||
1497 | struct seccomp_data sd; | ||
1498 | |||
1499 | sd.arch = arch; | ||
1500 | sd.nr = regs->orig_ax; | ||
1501 | sd.instruction_pointer = regs->ip; | ||
1502 | #ifdef CONFIG_X86_64 | ||
1503 | if (arch == AUDIT_ARCH_X86_64) { | ||
1504 | sd.args[0] = regs->di; | ||
1505 | sd.args[1] = regs->si; | ||
1506 | sd.args[2] = regs->dx; | ||
1507 | sd.args[3] = regs->r10; | ||
1508 | sd.args[4] = regs->r8; | ||
1509 | sd.args[5] = regs->r9; | ||
1510 | } else | ||
1511 | #endif | ||
1512 | { | ||
1513 | sd.args[0] = regs->bx; | ||
1514 | sd.args[1] = regs->cx; | ||
1515 | sd.args[2] = regs->dx; | ||
1516 | sd.args[3] = regs->si; | ||
1517 | sd.args[4] = regs->di; | ||
1518 | sd.args[5] = regs->bp; | ||
1519 | } | ||
1520 | |||
1521 | BUILD_BUG_ON(SECCOMP_PHASE1_OK != 0); | ||
1522 | BUILD_BUG_ON(SECCOMP_PHASE1_SKIP != 1); | ||
1523 | |||
1524 | ret = seccomp_phase1(&sd); | ||
1525 | if (ret == SECCOMP_PHASE1_SKIP) { | ||
1526 | regs->orig_ax = -1; | ||
1527 | ret = 0; | ||
1528 | } else if (ret != SECCOMP_PHASE1_OK) { | ||
1529 | return ret; /* Go directly to phase 2 */ | ||
1530 | } | ||
1531 | |||
1532 | work &= ~_TIF_SECCOMP; | ||
1533 | } | ||
1534 | #endif | ||
1535 | |||
1536 | /* Do our best to finish without phase 2. */ | ||
1537 | if (work == 0) | ||
1538 | return ret; /* seccomp and/or nohz only (ret == 0 here) */ | ||
1539 | |||
1540 | #ifdef CONFIG_AUDITSYSCALL | ||
1541 | if (work == _TIF_SYSCALL_AUDIT) { | ||
1542 | /* | ||
1543 | * If there is no more work to be done except auditing, | ||
1544 | * then audit in phase 1. Phase 2 always audits, so, if | ||
1545 | * we audit here, then we can't go on to phase 2. | ||
1546 | */ | ||
1547 | do_audit_syscall_entry(regs, arch); | ||
1548 | return 0; | ||
1549 | } | ||
1550 | #endif | ||
1551 | |||
1552 | return 1; /* Something is enabled that we can't handle in phase 1 */ | ||
1553 | } | ||
1554 | |||
1555 | /* Returns the syscall nr to run (which should match regs->orig_ax). */ | ||
1556 | long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch, | ||
1557 | unsigned long phase1_result) | ||
1558 | { | ||
1559 | long ret = 0; | ||
1560 | u32 work = ACCESS_ONCE(current_thread_info()->flags) & | ||
1561 | _TIF_WORK_SYSCALL_ENTRY; | ||
1562 | |||
1563 | BUG_ON(regs != task_pt_regs(current)); | ||
1458 | 1564 | ||
1459 | /* | 1565 | /* |
1460 | * If we stepped into a sysenter/syscall insn, it trapped in | 1566 | * If we stepped into a sysenter/syscall insn, it trapped in |
@@ -1463,17 +1569,21 @@ long syscall_trace_enter(struct pt_regs *regs) | |||
1463 | * do_debug() and we need to set it again to restore the user | 1569 | * do_debug() and we need to set it again to restore the user |
1464 | * state. If we entered on the slow path, TF was already set. | 1570 | * state. If we entered on the slow path, TF was already set. |
1465 | */ | 1571 | */ |
1466 | if (test_thread_flag(TIF_SINGLESTEP)) | 1572 | if (work & _TIF_SINGLESTEP) |
1467 | regs->flags |= X86_EFLAGS_TF; | 1573 | regs->flags |= X86_EFLAGS_TF; |
1468 | 1574 | ||
1469 | /* do the secure computing check first */ | 1575 | #ifdef CONFIG_SECCOMP |
1470 | if (secure_computing()) { | 1576 | /* |
1577 | * Call seccomp_phase2 before running the other hooks so that | ||
1578 | * they can see any changes made by a seccomp tracer. | ||
1579 | */ | ||
1580 | if (phase1_result > 1 && seccomp_phase2(phase1_result)) { | ||
1471 | /* seccomp failures shouldn't expose any additional code. */ | 1581 | /* seccomp failures shouldn't expose any additional code. */ |
1472 | ret = -1L; | 1582 | return -1; |
1473 | goto out; | ||
1474 | } | 1583 | } |
1584 | #endif | ||
1475 | 1585 | ||
1476 | if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) | 1586 | if (unlikely(work & _TIF_SYSCALL_EMU)) |
1477 | ret = -1L; | 1587 | ret = -1L; |
1478 | 1588 | ||
1479 | if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) && | 1589 | if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) && |
@@ -1483,23 +1593,22 @@ long syscall_trace_enter(struct pt_regs *regs) | |||
1483 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) | 1593 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
1484 | trace_sys_enter(regs, regs->orig_ax); | 1594 | trace_sys_enter(regs, regs->orig_ax); |
1485 | 1595 | ||
1486 | if (is_ia32_task()) | 1596 | do_audit_syscall_entry(regs, arch); |
1487 | audit_syscall_entry(AUDIT_ARCH_I386, | ||
1488 | regs->orig_ax, | ||
1489 | regs->bx, regs->cx, | ||
1490 | regs->dx, regs->si); | ||
1491 | #ifdef CONFIG_X86_64 | ||
1492 | else | ||
1493 | audit_syscall_entry(AUDIT_ARCH_X86_64, | ||
1494 | regs->orig_ax, | ||
1495 | regs->di, regs->si, | ||
1496 | regs->dx, regs->r10); | ||
1497 | #endif | ||
1498 | 1597 | ||
1499 | out: | ||
1500 | return ret ?: regs->orig_ax; | 1598 | return ret ?: regs->orig_ax; |
1501 | } | 1599 | } |
1502 | 1600 | ||
1601 | long syscall_trace_enter(struct pt_regs *regs) | ||
1602 | { | ||
1603 | u32 arch = is_ia32_task() ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; | ||
1604 | unsigned long phase1_result = syscall_trace_enter_phase1(regs, arch); | ||
1605 | |||
1606 | if (phase1_result == 0) | ||
1607 | return regs->orig_ax; | ||
1608 | else | ||
1609 | return syscall_trace_enter_phase2(regs, arch, phase1_result); | ||
1610 | } | ||
1611 | |||
1503 | void syscall_trace_leave(struct pt_regs *regs) | 1612 | void syscall_trace_leave(struct pt_regs *regs) |
1504 | { | 1613 | { |
1505 | bool step; | 1614 | bool step; |