Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'seccomp-v6.14-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull seccomp fix from Kees Cook:
"This is really a work-around for x86_64 having grown a syscall to
implement uretprobe, which has caused problems since v6.11.

This may change in the future, but for now, this fixes the unintended
seccomp filtering when uretprobe switched away from traps, and does so
with something that should be easy to backport.

- Allow uretprobe on x86_64 to avoid behavioral complications (Eyal
Birger)"

* tag 'seccomp-v6.14-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
selftests/seccomp: validate uretprobe syscall passes through seccomp
seccomp: passthrough uretprobe systemcall without filtering

+211
+12
kernel/seccomp.c
··· 749 749 if (WARN_ON_ONCE(!fprog)) 750 750 return false; 751 751 752 + /* Our single exception to filtering. */ 753 + #ifdef __NR_uretprobe 754 + #ifdef SECCOMP_ARCH_COMPAT 755 + if (sd->arch == SECCOMP_ARCH_NATIVE) 756 + #endif 757 + if (sd->nr == __NR_uretprobe) 758 + return true; 759 + #endif 760 + 752 761 for (pc = 0; pc < fprog->len; pc++) { 753 762 struct sock_filter *insn = &fprog->filter[pc]; 754 763 u16 code = insn->code; ··· 1032 1023 */ 1033 1024 static const int mode1_syscalls[] = { 1034 1025 __NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn, 1026 + #ifdef __NR_uretprobe 1027 + __NR_uretprobe, 1028 + #endif 1035 1029 -1, /* negative terminated */ 1036 1030 }; 1037 1031
+199
tools/testing/selftests/seccomp/seccomp_bpf.c
··· 47 47 #include <linux/kcmp.h> 48 48 #include <sys/resource.h> 49 49 #include <sys/capability.h> 50 + #include <linux/perf_event.h> 50 51 51 52 #include <unistd.h> 52 53 #include <sys/syscall.h> ··· 67 66 68 67 #ifndef PR_SET_PTRACER 69 68 # define PR_SET_PTRACER 0x59616d61 69 + #endif 70 + 71 + #ifndef noinline 72 + #define noinline __attribute__((noinline)) 70 73 #endif 71 74 72 75 #ifndef PR_SET_NO_NEW_PRIVS ··· 4891 4886 4892 4887 EXPECT_EQ(pid, waitpid(pid, &status, 0)); 4893 4888 EXPECT_EQ(0, status); 4889 + } 4890 + 4891 + noinline int probed(void) 4892 + { 4893 + return 1; 4894 + } 4895 + 4896 + static int parse_uint_from_file(const char *file, const char *fmt) 4897 + { 4898 + int err = -1, ret; 4899 + FILE *f; 4900 + 4901 + f = fopen(file, "re"); 4902 + if (f) { 4903 + err = fscanf(f, fmt, &ret); 4904 + fclose(f); 4905 + } 4906 + return err == 1 ? ret : err; 4907 + } 4908 + 4909 + static int determine_uprobe_perf_type(void) 4910 + { 4911 + const char *file = "/sys/bus/event_source/devices/uprobe/type"; 4912 + 4913 + return parse_uint_from_file(file, "%d\n"); 4914 + } 4915 + 4916 + static int determine_uprobe_retprobe_bit(void) 4917 + { 4918 + const char *file = "/sys/bus/event_source/devices/uprobe/format/retprobe"; 4919 + 4920 + return parse_uint_from_file(file, "config:%d\n"); 4921 + } 4922 + 4923 + static ssize_t get_uprobe_offset(const void *addr) 4924 + { 4925 + size_t start, base, end; 4926 + bool found = false; 4927 + char buf[256]; 4928 + FILE *f; 4929 + 4930 + f = fopen("/proc/self/maps", "r"); 4931 + if (!f) 4932 + return -1; 4933 + 4934 + while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) { 4935 + if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) { 4936 + found = true; 4937 + break; 4938 + } 4939 + } 4940 + fclose(f); 4941 + return found ? (uintptr_t)addr - start + base : -1; 4942 + } 4943 + 4944 + FIXTURE(URETPROBE) { 4945 + int fd; 4946 + }; 4947 + 4948 + FIXTURE_VARIANT(URETPROBE) { 4949 + /* 4950 + * All of the URETPROBE behaviors can be tested with either 4951 + * uretprobe attached or not 4952 + */ 4953 + bool attach; 4954 + }; 4955 + 4956 + FIXTURE_VARIANT_ADD(URETPROBE, attached) { 4957 + .attach = true, 4958 + }; 4959 + 4960 + FIXTURE_VARIANT_ADD(URETPROBE, not_attached) { 4961 + .attach = false, 4962 + }; 4963 + 4964 + FIXTURE_SETUP(URETPROBE) 4965 + { 4966 + const size_t attr_sz = sizeof(struct perf_event_attr); 4967 + struct perf_event_attr attr; 4968 + ssize_t offset; 4969 + int type, bit; 4970 + 4971 + #ifndef __NR_uretprobe 4972 + SKIP(return, "__NR_uretprobe syscall not defined"); 4973 + #endif 4974 + 4975 + if (!variant->attach) 4976 + return; 4977 + 4978 + memset(&attr, 0, attr_sz); 4979 + 4980 + type = determine_uprobe_perf_type(); 4981 + ASSERT_GE(type, 0); 4982 + bit = determine_uprobe_retprobe_bit(); 4983 + ASSERT_GE(bit, 0); 4984 + offset = get_uprobe_offset(probed); 4985 + ASSERT_GE(offset, 0); 4986 + 4987 + attr.config |= 1 << bit; 4988 + attr.size = attr_sz; 4989 + attr.type = type; 4990 + attr.config1 = ptr_to_u64("/proc/self/exe"); 4991 + attr.config2 = offset; 4992 + 4993 + self->fd = syscall(__NR_perf_event_open, &attr, 4994 + getpid() /* pid */, -1 /* cpu */, -1 /* group_fd */, 4995 + PERF_FLAG_FD_CLOEXEC); 4996 + } 4997 + 4998 + FIXTURE_TEARDOWN(URETPROBE) 4999 + { 5000 + /* we could call close(self->fd), but we'd need extra filter for 5001 + * that and since we are calling _exit right away.. 5002 + */ 5003 + } 5004 + 5005 + static int run_probed_with_filter(struct sock_fprog *prog) 5006 + { 5007 + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || 5008 + seccomp(SECCOMP_SET_MODE_FILTER, 0, prog)) { 5009 + return -1; 5010 + } 5011 + 5012 + probed(); 5013 + return 0; 5014 + } 5015 + 5016 + TEST_F(URETPROBE, uretprobe_default_allow) 5017 + { 5018 + struct sock_filter filter[] = { 5019 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 5020 + }; 5021 + struct sock_fprog prog = { 5022 + .len = (unsigned short)ARRAY_SIZE(filter), 5023 + .filter = filter, 5024 + }; 5025 + 5026 + ASSERT_EQ(0, run_probed_with_filter(&prog)); 5027 + } 5028 + 5029 + TEST_F(URETPROBE, uretprobe_default_block) 5030 + { 5031 + struct sock_filter filter[] = { 5032 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 5033 + offsetof(struct seccomp_data, nr)), 5034 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_exit_group, 1, 0), 5035 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 5036 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 5037 + }; 5038 + struct sock_fprog prog = { 5039 + .len = (unsigned short)ARRAY_SIZE(filter), 5040 + .filter = filter, 5041 + }; 5042 + 5043 + ASSERT_EQ(0, run_probed_with_filter(&prog)); 5044 + } 5045 + 5046 + TEST_F(URETPROBE, uretprobe_block_uretprobe_syscall) 5047 + { 5048 + struct sock_filter filter[] = { 5049 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 5050 + offsetof(struct seccomp_data, nr)), 5051 + #ifdef __NR_uretprobe 5052 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uretprobe, 0, 1), 5053 + #endif 5054 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 5055 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 5056 + }; 5057 + struct sock_fprog prog = { 5058 + .len = (unsigned short)ARRAY_SIZE(filter), 5059 + .filter = filter, 5060 + }; 5061 + 5062 + ASSERT_EQ(0, run_probed_with_filter(&prog)); 5063 + } 5064 + 5065 + TEST_F(URETPROBE, uretprobe_default_block_with_uretprobe_syscall) 5066 + { 5067 + struct sock_filter filter[] = { 5068 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 5069 + offsetof(struct seccomp_data, nr)), 5070 + #ifdef __NR_uretprobe 5071 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uretprobe, 2, 0), 5072 + #endif 5073 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_exit_group, 1, 0), 5074 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 5075 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 5076 + }; 5077 + struct sock_fprog prog = { 5078 + .len = (unsigned short)ARRAY_SIZE(filter), 5079 + .filter = filter, 5080 + }; 5081 + 5082 + ASSERT_EQ(0, run_probed_with_filter(&prog)); 4894 5083 } 4895 5084 4896 5085 /*