1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2025 Google LLC. */ 3 4 #include <linux/bpf.h> 5 #include <bpf/bpf_helpers.h> 6 #include "../../../include/linux/filter.h" 7 #include "bpf_misc.h" 8 9 #ifdef CAN_USE_LOAD_ACQ_STORE_REL 10 11 SEC("socket") 12 __description("store-release, 8-bit") 13 __success __success_unpriv __retval(0) 14 __naked void store_release_8(void) 15 { 16 asm volatile ( 17 "r0 = 0;" 18 "w1 = 0x12;" 19 ".8byte %[store_release_insn];" // store_release((u8 *)(r10 - 1), w1); 20 "w2 = *(u8 *)(r10 - 1);" 21 "if r2 == r1 goto 1f;" 22 "r0 = 1;" 23 "1:" 24 "exit;" 25 : 26 : __imm_insn(store_release_insn, 27 BPF_ATOMIC_OP(BPF_B, BPF_STORE_REL, BPF_REG_10, BPF_REG_1, -1)) 28 : __clobber_all); 29 } 30 31 SEC("socket") 32 __description("store-release, 16-bit") 33 __success __success_unpriv __retval(0) 34 __naked void store_release_16(void) 35 { 36 asm volatile ( 37 "r0 = 0;" 38 "w1 = 0x1234;" 39 ".8byte %[store_release_insn];" // store_release((u16 *)(r10 - 2), w1); 40 "w2 = *(u16 *)(r10 - 2);" 41 "if r2 == r1 goto 1f;" 42 "r0 = 1;" 43 "1:" 44 "exit;" 45 : 46 : __imm_insn(store_release_insn, 47 BPF_ATOMIC_OP(BPF_H, BPF_STORE_REL, BPF_REG_10, BPF_REG_1, -2)) 48 : __clobber_all); 49 } 50 51 SEC("socket") 52 __description("store-release, 32-bit") 53 __success __success_unpriv __retval(0) 54 __naked void store_release_32(void) 55 { 56 asm volatile ( 57 "r0 = 0;" 58 "w1 = 0x12345678;" 59 ".8byte %[store_release_insn];" // store_release((u32 *)(r10 - 4), w1); 60 "w2 = *(u32 *)(r10 - 4);" 61 "if r2 == r1 goto 1f;" 62 "r0 = 1;" 63 "1:" 64 "exit;" 65 : 66 : __imm_insn(store_release_insn, 67 BPF_ATOMIC_OP(BPF_W, BPF_STORE_REL, BPF_REG_10, BPF_REG_1, -4)) 68 : __clobber_all); 69 } 70 71 SEC("socket") 72 __description("store-release, 64-bit") 73 __success __success_unpriv __retval(0) 74 __naked void store_release_64(void) 75 { 76 asm volatile ( 77 "r0 = 0;" 78 "r1 = 0x1234567890abcdef ll;" 79 ".8byte %[store_release_insn];" // store_release((u64 *)(r10 - 8), r1); 80 "r2 = *(u64 *)(r10 - 8);" 81 "if r2 == r1 goto 1f;" 82 "r0 = 1;" 83 "1:" 84 "exit;" 85 : 86 : __imm_insn(store_release_insn, 87 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_10, BPF_REG_1, -8)) 88 : __clobber_all); 89 } 90 91 SEC("socket") 92 __description("store-release with uninitialized src_reg") 93 __failure __failure_unpriv __msg("R2 !read_ok") 94 __naked void store_release_with_uninitialized_src_reg(void) 95 { 96 asm volatile ( 97 ".8byte %[store_release_insn];" // store_release((u64 *)(r10 - 8), r2); 98 "exit;" 99 : 100 : __imm_insn(store_release_insn, 101 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_10, BPF_REG_2, -8)) 102 : __clobber_all); 103 } 104 105 SEC("socket") 106 __description("store-release with uninitialized dst_reg") 107 __failure __failure_unpriv __msg("R2 !read_ok") 108 __naked void store_release_with_uninitialized_dst_reg(void) 109 { 110 asm volatile ( 111 "r1 = 0;" 112 ".8byte %[store_release_insn];" // store_release((u64 *)(r2 - 8), r1); 113 "exit;" 114 : 115 : __imm_insn(store_release_insn, 116 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_2, BPF_REG_1, -8)) 117 : __clobber_all); 118 } 119 120 SEC("socket") 121 __description("store-release with non-pointer dst_reg") 122 __failure __failure_unpriv __msg("R1 invalid mem access 'scalar'") 123 __naked void store_release_with_non_pointer_dst_reg(void) 124 { 125 asm volatile ( 126 "r1 = 0;" 127 ".8byte %[store_release_insn];" // store_release((u64 *)(r1 + 0), r1); 128 "exit;" 129 : 130 : __imm_insn(store_release_insn, 131 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_1, BPF_REG_1, 0)) 132 : __clobber_all); 133 } 134 135 SEC("socket") 136 __description("misaligned store-release") 137 __failure __failure_unpriv __msg("misaligned stack access off") 138 __flag(BPF_F_ANY_ALIGNMENT) 139 __naked void store_release_misaligned(void) 140 { 141 asm volatile ( 142 "w0 = 0;" 143 ".8byte %[store_release_insn];" // store_release((u32 *)(r10 - 5), w0); 144 "exit;" 145 : 146 : __imm_insn(store_release_insn, 147 BPF_ATOMIC_OP(BPF_W, BPF_STORE_REL, BPF_REG_10, BPF_REG_0, -5)) 148 : __clobber_all); 149 } 150 151 SEC("socket") 152 __description("store-release to ctx pointer") 153 __failure __failure_unpriv __msg("BPF_ATOMIC stores into R1 ctx is not allowed") 154 __naked void store_release_to_ctx_pointer(void) 155 { 156 asm volatile ( 157 "w0 = 0;" 158 // store_release((u8 *)(r1 + offsetof(struct __sk_buff, cb[0])), w0); 159 ".8byte %[store_release_insn];" 160 "exit;" 161 : 162 : __imm_insn(store_release_insn, 163 BPF_ATOMIC_OP(BPF_B, BPF_STORE_REL, BPF_REG_1, BPF_REG_0, 164 offsetof(struct __sk_buff, cb[0]))) 165 : __clobber_all); 166 } 167 168 SEC("xdp") 169 __description("store-release to pkt pointer") 170 __failure __msg("BPF_ATOMIC stores into R2 pkt is not allowed") 171 __naked void store_release_to_pkt_pointer(void) 172 { 173 asm volatile ( 174 "w0 = 0;" 175 "r2 = *(u32 *)(r1 + %[xdp_md_data]);" 176 "r3 = *(u32 *)(r1 + %[xdp_md_data_end]);" 177 "r1 = r2;" 178 "r1 += 8;" 179 "if r1 >= r3 goto l0_%=;" 180 ".8byte %[store_release_insn];" // store_release((u8 *)(r2 + 0), w0); 181 "l0_%=: r0 = 0;" 182 "exit;" 183 : 184 : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)), 185 __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end)), 186 __imm_insn(store_release_insn, 187 BPF_ATOMIC_OP(BPF_B, BPF_STORE_REL, BPF_REG_2, BPF_REG_0, 0)) 188 : __clobber_all); 189 } 190 191 SEC("flow_dissector") 192 __description("store-release to flow_keys pointer") 193 __failure __msg("BPF_ATOMIC stores into R2 flow_keys is not allowed") 194 __naked void store_release_to_flow_keys_pointer(void) 195 { 196 asm volatile ( 197 "w0 = 0;" 198 "r2 = *(u64 *)(r1 + %[__sk_buff_flow_keys]);" 199 ".8byte %[store_release_insn];" // store_release((u8 *)(r2 + 0), w0); 200 "exit;" 201 : 202 : __imm_const(__sk_buff_flow_keys, 203 offsetof(struct __sk_buff, flow_keys)), 204 __imm_insn(store_release_insn, 205 BPF_ATOMIC_OP(BPF_B, BPF_STORE_REL, BPF_REG_2, BPF_REG_0, 0)) 206 : __clobber_all); 207 } 208 209 SEC("sk_reuseport") 210 __description("store-release to sock pointer") 211 __failure __msg("R2 cannot write into sock") 212 __naked void store_release_to_sock_pointer(void) 213 { 214 asm volatile ( 215 "w0 = 0;" 216 "r2 = *(u64 *)(r1 + %[sk_reuseport_md_sk]);" 217 ".8byte %[store_release_insn];" // store_release((u8 *)(r2 + 0), w0); 218 "exit;" 219 : 220 : __imm_const(sk_reuseport_md_sk, offsetof(struct sk_reuseport_md, sk)), 221 __imm_insn(store_release_insn, 222 BPF_ATOMIC_OP(BPF_B, BPF_STORE_REL, BPF_REG_2, BPF_REG_0, 0)) 223 : __clobber_all); 224 } 225 226 SEC("socket") 227 __description("store-release, leak pointer to stack") 228 __success __success_unpriv __retval(0) 229 __naked void store_release_leak_pointer_to_stack(void) 230 { 231 asm volatile ( 232 ".8byte %[store_release_insn];" // store_release((u64 *)(r10 - 8), r1); 233 "r0 = 0;" 234 "exit;" 235 : 236 : __imm_insn(store_release_insn, 237 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_10, BPF_REG_1, -8)) 238 : __clobber_all); 239 } 240 241 struct { 242 __uint(type, BPF_MAP_TYPE_HASH); 243 __uint(max_entries, 1); 244 __type(key, long long); 245 __type(value, long long); 246 } map_hash_8b SEC(".maps"); 247 248 SEC("socket") 249 __description("store-release, leak pointer to map") 250 __success __retval(0) 251 __failure_unpriv __msg_unpriv("R6 leaks addr into map") 252 __naked void store_release_leak_pointer_to_map(void) 253 { 254 asm volatile ( 255 "r6 = r1;" 256 "r1 = %[map_hash_8b] ll;" 257 "r2 = 0;" 258 "*(u64 *)(r10 - 8) = r2;" 259 "r2 = r10;" 260 "r2 += -8;" 261 "call %[bpf_map_lookup_elem];" 262 "if r0 == 0 goto l0_%=;" 263 ".8byte %[store_release_insn];" // store_release((u64 *)(r0 + 0), r6); 264 "l0_%=:" 265 "r0 = 0;" 266 "exit;" 267 : 268 : __imm_addr(map_hash_8b), 269 __imm(bpf_map_lookup_elem), 270 __imm_insn(store_release_insn, 271 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_0, BPF_REG_6, 0)) 272 : __clobber_all); 273 } 274 275 SEC("socket") 276 __description("store-release with invalid register R15") 277 __failure __failure_unpriv __msg("R15 is invalid") 278 __naked void store_release_with_invalid_reg(void) 279 { 280 asm volatile ( 281 ".8byte %[store_release_insn];" // store_release((u64 *)(r15 + 0), r1); 282 "exit;" 283 : 284 : __imm_insn(store_release_insn, 285 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, 15 /* invalid reg */, BPF_REG_1, 0)) 286 : __clobber_all); 287 } 288 289 #else /* CAN_USE_LOAD_ACQ_STORE_REL */ 290 291 SEC("socket") 292 __description("Clang version < 18, ENABLE_ATOMICS_TESTS not defined, and/or JIT doesn't support store-release, use a dummy test") 293 __success 294 int dummy_test(void) 295 { 296 return 0; 297 } 298 299 #endif /* CAN_USE_LOAD_ACQ_STORE_REL */ 300 301 char _license[] SEC("license") = "GPL"; 302