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