|
68 | 68 | #define SECCOMP_MODE_FILTER 2 |
69 | 69 | #endif |
70 | 70 |
|
71 | | -#ifndef SECCOMP_RET_KILL_THREAD |
| 71 | +#ifndef SECCOMP_RET_ALLOW |
| 72 | +struct seccomp_data { |
| 73 | + int nr; |
| 74 | + __u32 arch; |
| 75 | + __u64 instruction_pointer; |
| 76 | + __u64 args[6]; |
| 77 | +}; |
| 78 | +#endif |
| 79 | + |
| 80 | +#ifndef SECCOMP_RET_KILL_PROCESS |
| 81 | +#define SECCOMP_RET_KILL_PROCESS 0x80000000U /* kill the process */ |
72 | 82 | #define SECCOMP_RET_KILL_THREAD 0x00000000U /* kill the thread */ |
73 | 83 | #endif |
74 | 84 | #ifndef SECCOMP_RET_KILL |
|
82 | 92 | #define SECCOMP_RET_LOG 0x7ffc0000U /* allow after logging */ |
83 | 93 | #endif |
84 | 94 |
|
85 | | -#ifndef SECCOMP_RET_ACTION |
86 | | -/* Masks for the return value sections. */ |
87 | | -#define SECCOMP_RET_ACTION 0x7fff0000U |
88 | | -#define SECCOMP_RET_DATA 0x0000ffffU |
| 95 | +#ifndef __NR_seccomp |
| 96 | +# if defined(__i386__) |
| 97 | +# define __NR_seccomp 354 |
| 98 | +# elif defined(__x86_64__) |
| 99 | +# define __NR_seccomp 317 |
| 100 | +# elif defined(__arm__) |
| 101 | +# define __NR_seccomp 383 |
| 102 | +# elif defined(__aarch64__) |
| 103 | +# define __NR_seccomp 277 |
| 104 | +# elif defined(__hppa__) |
| 105 | +# define __NR_seccomp 338 |
| 106 | +# elif defined(__powerpc__) |
| 107 | +# define __NR_seccomp 358 |
| 108 | +# elif defined(__s390__) |
| 109 | +# define __NR_seccomp 348 |
| 110 | +# else |
| 111 | +# warning "seccomp syscall number unknown for this architecture" |
| 112 | +# define __NR_seccomp 0xffff |
| 113 | +# endif |
| 114 | +#endif |
89 | 115 |
|
90 | | -struct seccomp_data { |
91 | | - int nr; |
92 | | - __u32 arch; |
93 | | - __u64 instruction_pointer; |
94 | | - __u64 args[6]; |
95 | | -}; |
| 116 | +#ifndef SECCOMP_SET_MODE_STRICT |
| 117 | +#define SECCOMP_SET_MODE_STRICT 0 |
| 118 | +#endif |
| 119 | + |
| 120 | +#ifndef SECCOMP_SET_MODE_FILTER |
| 121 | +#define SECCOMP_SET_MODE_FILTER 1 |
| 122 | +#endif |
| 123 | + |
| 124 | +#ifndef SECCOMP_GET_ACTION_AVAIL |
| 125 | +#define SECCOMP_GET_ACTION_AVAIL 2 |
| 126 | +#endif |
| 127 | + |
| 128 | +#ifndef SECCOMP_FILTER_FLAG_TSYNC |
| 129 | +#define SECCOMP_FILTER_FLAG_TSYNC 1 |
| 130 | +#endif |
| 131 | + |
| 132 | +#ifndef SECCOMP_FILTER_FLAG_LOG |
| 133 | +#define SECCOMP_FILTER_FLAG_LOG 2 |
| 134 | +#endif |
| 135 | + |
| 136 | +#ifndef seccomp |
| 137 | +int seccomp(unsigned int op, unsigned int flags, void *args) |
| 138 | +{ |
| 139 | + errno = 0; |
| 140 | + return syscall(__NR_seccomp, op, flags, args); |
| 141 | +} |
96 | 142 | #endif |
97 | 143 |
|
98 | 144 | #if __BYTE_ORDER == __LITTLE_ENDIAN |
@@ -550,6 +596,117 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS) |
550 | 596 | close(fd); |
551 | 597 | } |
552 | 598 |
|
| 599 | +/* This is a thread task to die via seccomp filter violation. */ |
| 600 | +void *kill_thread(void *data) |
| 601 | +{ |
| 602 | + bool die = (bool)data; |
| 603 | + |
| 604 | + if (die) { |
| 605 | + prctl(PR_GET_SECCOMP, 0, 0, 0, 0); |
| 606 | + return (void *)SIBLING_EXIT_FAILURE; |
| 607 | + } |
| 608 | + |
| 609 | + return (void *)SIBLING_EXIT_UNKILLED; |
| 610 | +} |
| 611 | + |
| 612 | +/* Prepare a thread that will kill itself or both of us. */ |
| 613 | +void kill_thread_or_group(struct __test_metadata *_metadata, bool kill_process) |
| 614 | +{ |
| 615 | + pthread_t thread; |
| 616 | + void *status; |
| 617 | + /* Kill only when calling __NR_prctl. */ |
| 618 | + struct sock_filter filter_thread[] = { |
| 619 | + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, |
| 620 | + offsetof(struct seccomp_data, nr)), |
| 621 | + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1), |
| 622 | + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD), |
| 623 | + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), |
| 624 | + }; |
| 625 | + struct sock_fprog prog_thread = { |
| 626 | + .len = (unsigned short)ARRAY_SIZE(filter_thread), |
| 627 | + .filter = filter_thread, |
| 628 | + }; |
| 629 | + struct sock_filter filter_process[] = { |
| 630 | + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, |
| 631 | + offsetof(struct seccomp_data, nr)), |
| 632 | + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1), |
| 633 | + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_PROCESS), |
| 634 | + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), |
| 635 | + }; |
| 636 | + struct sock_fprog prog_process = { |
| 637 | + .len = (unsigned short)ARRAY_SIZE(filter_process), |
| 638 | + .filter = filter_process, |
| 639 | + }; |
| 640 | + |
| 641 | + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { |
| 642 | + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); |
| 643 | + } |
| 644 | + |
| 645 | + ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, |
| 646 | + kill_process ? &prog_process : &prog_thread)); |
| 647 | + |
| 648 | + /* |
| 649 | + * Add the KILL_THREAD rule again to make sure that the KILL_PROCESS |
| 650 | + * flag cannot be downgraded by a new filter. |
| 651 | + */ |
| 652 | + ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog_thread)); |
| 653 | + |
| 654 | + /* Start a thread that will exit immediately. */ |
| 655 | + ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)false)); |
| 656 | + ASSERT_EQ(0, pthread_join(thread, &status)); |
| 657 | + ASSERT_EQ(SIBLING_EXIT_UNKILLED, (unsigned long)status); |
| 658 | + |
| 659 | + /* Start a thread that will die immediately. */ |
| 660 | + ASSERT_EQ(0, pthread_create(&thread, NULL, kill_thread, (void *)true)); |
| 661 | + ASSERT_EQ(0, pthread_join(thread, &status)); |
| 662 | + ASSERT_NE(SIBLING_EXIT_FAILURE, (unsigned long)status); |
| 663 | + |
| 664 | + /* |
| 665 | + * If we get here, only the spawned thread died. Let the parent know |
| 666 | + * the whole process didn't die (i.e. this thread, the spawner, |
| 667 | + * stayed running). |
| 668 | + */ |
| 669 | + exit(42); |
| 670 | +} |
| 671 | + |
| 672 | +TEST(KILL_thread) |
| 673 | +{ |
| 674 | + int status; |
| 675 | + pid_t child_pid; |
| 676 | + |
| 677 | + child_pid = fork(); |
| 678 | + ASSERT_LE(0, child_pid); |
| 679 | + if (child_pid == 0) { |
| 680 | + kill_thread_or_group(_metadata, false); |
| 681 | + _exit(38); |
| 682 | + } |
| 683 | + |
| 684 | + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); |
| 685 | + |
| 686 | + /* If only the thread was killed, we'll see exit 42. */ |
| 687 | + ASSERT_TRUE(WIFEXITED(status)); |
| 688 | + ASSERT_EQ(42, WEXITSTATUS(status)); |
| 689 | +} |
| 690 | + |
| 691 | +TEST(KILL_process) |
| 692 | +{ |
| 693 | + int status; |
| 694 | + pid_t child_pid; |
| 695 | + |
| 696 | + child_pid = fork(); |
| 697 | + ASSERT_LE(0, child_pid); |
| 698 | + if (child_pid == 0) { |
| 699 | + kill_thread_or_group(_metadata, true); |
| 700 | + _exit(38); |
| 701 | + } |
| 702 | + |
| 703 | + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); |
| 704 | + |
| 705 | + /* If the entire process was killed, we'll see SIGSYS. */ |
| 706 | + ASSERT_TRUE(WIFSIGNALED(status)); |
| 707 | + ASSERT_EQ(SIGSYS, WTERMSIG(status)); |
| 708 | +} |
| 709 | + |
553 | 710 | /* TODO(wad) add 64-bit versus 32-bit arg tests. */ |
554 | 711 | TEST(arg_out_of_range) |
555 | 712 | { |
@@ -1800,55 +1957,6 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_ptrace, SIGSYS) |
1800 | 1957 | EXPECT_NE(self->mypid, syscall(__NR_getpid)); |
1801 | 1958 | } |
1802 | 1959 |
|
1803 | | -#ifndef __NR_seccomp |
1804 | | -# if defined(__i386__) |
1805 | | -# define __NR_seccomp 354 |
1806 | | -# elif defined(__x86_64__) |
1807 | | -# define __NR_seccomp 317 |
1808 | | -# elif defined(__arm__) |
1809 | | -# define __NR_seccomp 383 |
1810 | | -# elif defined(__aarch64__) |
1811 | | -# define __NR_seccomp 277 |
1812 | | -# elif defined(__hppa__) |
1813 | | -# define __NR_seccomp 338 |
1814 | | -# elif defined(__powerpc__) |
1815 | | -# define __NR_seccomp 358 |
1816 | | -# elif defined(__s390__) |
1817 | | -# define __NR_seccomp 348 |
1818 | | -# else |
1819 | | -# warning "seccomp syscall number unknown for this architecture" |
1820 | | -# define __NR_seccomp 0xffff |
1821 | | -# endif |
1822 | | -#endif |
1823 | | - |
1824 | | -#ifndef SECCOMP_SET_MODE_STRICT |
1825 | | -#define SECCOMP_SET_MODE_STRICT 0 |
1826 | | -#endif |
1827 | | - |
1828 | | -#ifndef SECCOMP_SET_MODE_FILTER |
1829 | | -#define SECCOMP_SET_MODE_FILTER 1 |
1830 | | -#endif |
1831 | | - |
1832 | | -#ifndef SECCOMP_GET_ACTION_AVAIL |
1833 | | -#define SECCOMP_GET_ACTION_AVAIL 2 |
1834 | | -#endif |
1835 | | - |
1836 | | -#ifndef SECCOMP_FILTER_FLAG_TSYNC |
1837 | | -#define SECCOMP_FILTER_FLAG_TSYNC 1 |
1838 | | -#endif |
1839 | | - |
1840 | | -#ifndef SECCOMP_FILTER_FLAG_LOG |
1841 | | -#define SECCOMP_FILTER_FLAG_LOG 2 |
1842 | | -#endif |
1843 | | - |
1844 | | -#ifndef seccomp |
1845 | | -int seccomp(unsigned int op, unsigned int flags, void *args) |
1846 | | -{ |
1847 | | - errno = 0; |
1848 | | - return syscall(__NR_seccomp, op, flags, args); |
1849 | | -} |
1850 | | -#endif |
1851 | | - |
1852 | 1960 | TEST(seccomp_syscall) |
1853 | 1961 | { |
1854 | 1962 | struct sock_filter filter[] = { |
|
0 commit comments