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.

selftests/seccomp: validate uprobe syscall passes through seccomp

Adding uprobe checks into the current uretprobe tests.

All the related tests are now executed with attached uprobe
or uretprobe or without any probe.

Renaming the test fixture to uprobe, because it seems better.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250720112133.244369-22-jolsa@kernel.org

authored by

Jiri Olsa and committed by
Peter Zijlstra
9ffc7a63 89d1d843

+88 -23
+88 -23
tools/testing/selftests/seccomp/seccomp_bpf.c
··· 73 73 #define noinline __attribute__((noinline)) 74 74 #endif 75 75 76 + #ifndef __nocf_check 77 + #define __nocf_check __attribute__((nocf_check)) 78 + #endif 79 + 80 + #ifndef __naked 81 + #define __naked __attribute__((__naked__)) 82 + #endif 83 + 76 84 #ifndef PR_SET_NO_NEW_PRIVS 77 85 #define PR_SET_NO_NEW_PRIVS 38 78 86 #define PR_GET_NO_NEW_PRIVS 39 ··· 4904 4896 EXPECT_EQ(0, status); 4905 4897 } 4906 4898 4907 - noinline int probed(void) 4899 + #ifdef __x86_64__ 4900 + 4901 + /* 4902 + * We need naked probed_uprobe function. Using __nocf_check 4903 + * check to skip possible endbr64 instruction and ignoring 4904 + * -Wattributes, otherwise the compilation might fail. 4905 + */ 4906 + #pragma GCC diagnostic push 4907 + #pragma GCC diagnostic ignored "-Wattributes" 4908 + 4909 + __naked __nocf_check noinline int probed_uprobe(void) 4910 + { 4911 + /* 4912 + * Optimized uprobe is possible only on top of nop5 instruction. 4913 + */ 4914 + asm volatile (" \n" 4915 + ".byte 0x0f, 0x1f, 0x44, 0x00, 0x00 \n" 4916 + "ret \n" 4917 + ); 4918 + } 4919 + #pragma GCC diagnostic pop 4920 + 4921 + #else 4922 + noinline int probed_uprobe(void) 4923 + { 4924 + return 1; 4925 + } 4926 + #endif 4927 + 4928 + noinline int probed_uretprobe(void) 4908 4929 { 4909 4930 return 1; 4910 4931 } ··· 4986 4949 return found ? (uintptr_t)addr - start + base : -1; 4987 4950 } 4988 4951 4989 - FIXTURE(URETPROBE) { 4952 + FIXTURE(UPROBE) { 4990 4953 int fd; 4991 4954 }; 4992 4955 4993 - FIXTURE_VARIANT(URETPROBE) { 4956 + FIXTURE_VARIANT(UPROBE) { 4994 4957 /* 4995 - * All of the URETPROBE behaviors can be tested with either 4996 - * uretprobe attached or not 4958 + * All of the U(RET)PROBE behaviors can be tested with either 4959 + * u(ret)probe attached or not 4997 4960 */ 4998 4961 bool attach; 4962 + /* 4963 + * Test both uprobe and uretprobe. 4964 + */ 4965 + bool uretprobe; 4999 4966 }; 5000 4967 5001 - FIXTURE_VARIANT_ADD(URETPROBE, attached) { 5002 - .attach = true, 5003 - }; 5004 - 5005 - FIXTURE_VARIANT_ADD(URETPROBE, not_attached) { 4968 + FIXTURE_VARIANT_ADD(UPROBE, not_attached) { 5006 4969 .attach = false, 4970 + .uretprobe = false, 5007 4971 }; 5008 4972 5009 - FIXTURE_SETUP(URETPROBE) 4973 + FIXTURE_VARIANT_ADD(UPROBE, uprobe_attached) { 4974 + .attach = true, 4975 + .uretprobe = false, 4976 + }; 4977 + 4978 + FIXTURE_VARIANT_ADD(UPROBE, uretprobe_attached) { 4979 + .attach = true, 4980 + .uretprobe = true, 4981 + }; 4982 + 4983 + FIXTURE_SETUP(UPROBE) 5010 4984 { 5011 4985 const size_t attr_sz = sizeof(struct perf_event_attr); 5012 4986 struct perf_event_attr attr; 5013 4987 ssize_t offset; 5014 4988 int type, bit; 5015 4989 5016 - #ifndef __NR_uretprobe 5017 - SKIP(return, "__NR_uretprobe syscall not defined"); 4990 + #if !defined(__NR_uprobe) || !defined(__NR_uretprobe) 4991 + SKIP(return, "__NR_uprobe ot __NR_uretprobe syscalls not defined"); 5018 4992 #endif 5019 4993 5020 4994 if (!variant->attach) ··· 5035 4987 5036 4988 type = determine_uprobe_perf_type(); 5037 4989 ASSERT_GE(type, 0); 5038 - bit = determine_uprobe_retprobe_bit(); 5039 - ASSERT_GE(bit, 0); 5040 - offset = get_uprobe_offset(probed); 4990 + 4991 + if (variant->uretprobe) { 4992 + bit = determine_uprobe_retprobe_bit(); 4993 + ASSERT_GE(bit, 0); 4994 + } 4995 + 4996 + offset = get_uprobe_offset(variant->uretprobe ? probed_uretprobe : probed_uprobe); 5041 4997 ASSERT_GE(offset, 0); 5042 4998 5043 - attr.config |= 1 << bit; 4999 + if (variant->uretprobe) 5000 + attr.config |= 1 << bit; 5044 5001 attr.size = attr_sz; 5045 5002 attr.type = type; 5046 5003 attr.config1 = ptr_to_u64("/proc/self/exe"); ··· 5056 5003 PERF_FLAG_FD_CLOEXEC); 5057 5004 } 5058 5005 5059 - FIXTURE_TEARDOWN(URETPROBE) 5006 + FIXTURE_TEARDOWN(UPROBE) 5060 5007 { 5061 5008 /* we could call close(self->fd), but we'd need extra filter for 5062 5009 * that and since we are calling _exit right away.. ··· 5070 5017 return -1; 5071 5018 } 5072 5019 5073 - probed(); 5020 + /* 5021 + * Uprobe is optimized after first hit, so let's hit twice. 5022 + */ 5023 + probed_uprobe(); 5024 + probed_uprobe(); 5025 + 5026 + probed_uretprobe(); 5074 5027 return 0; 5075 5028 } 5076 5029 5077 - TEST_F(URETPROBE, uretprobe_default_allow) 5030 + TEST_F(UPROBE, uprobe_default_allow) 5078 5031 { 5079 5032 struct sock_filter filter[] = { 5080 5033 BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), ··· 5093 5034 ASSERT_EQ(0, run_probed_with_filter(&prog)); 5094 5035 } 5095 5036 5096 - TEST_F(URETPROBE, uretprobe_default_block) 5037 + TEST_F(UPROBE, uprobe_default_block) 5097 5038 { 5098 5039 struct sock_filter filter[] = { 5099 5040 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, ··· 5110 5051 ASSERT_EQ(0, run_probed_with_filter(&prog)); 5111 5052 } 5112 5053 5113 - TEST_F(URETPROBE, uretprobe_block_uretprobe_syscall) 5054 + TEST_F(UPROBE, uprobe_block_syscall) 5114 5055 { 5115 5056 struct sock_filter filter[] = { 5116 5057 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 5117 5058 offsetof(struct seccomp_data, nr)), 5059 + #ifdef __NR_uprobe 5060 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uprobe, 1, 2), 5061 + #endif 5118 5062 #ifdef __NR_uretprobe 5119 5063 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uretprobe, 0, 1), 5120 5064 #endif ··· 5132 5070 ASSERT_EQ(0, run_probed_with_filter(&prog)); 5133 5071 } 5134 5072 5135 - TEST_F(URETPROBE, uretprobe_default_block_with_uretprobe_syscall) 5073 + TEST_F(UPROBE, uprobe_default_block_with_syscall) 5136 5074 { 5137 5075 struct sock_filter filter[] = { 5138 5076 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 5139 5077 offsetof(struct seccomp_data, nr)), 5078 + #ifdef __NR_uprobe 5079 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uprobe, 3, 0), 5080 + #endif 5140 5081 #ifdef __NR_uretprobe 5141 5082 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uretprobe, 2, 0), 5142 5083 #endif