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 ".8byte %[store_release_insn];" // store_release((u8 *)(r1 + 0), w0); 144 "exit;" 145 : 146 : __imm_insn(store_release_insn, 147 BPF_ATOMIC_OP(BPF_B, BPF_STORE_REL, BPF_REG_1, BPF_REG_0, 0)) 148 : __clobber_all); 149 } 150 151 SEC("xdp") 152 __description("store-release to pkt pointer") 153 __failure __msg("BPF_ATOMIC stores into R2 pkt is not allowed") 154 __naked void store_release_to_pkt_pointer(void) 155 { 156 asm volatile ( 157 "w0 = 0;" 158 "r2 = *(u32 *)(r1 + %[xdp_md_data]);" 159 ".8byte %[store_release_insn];" // store_release((u8 *)(r2 + 0), w0); 160 "exit;" 161 : 162 : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)), 163 __imm_insn(store_release_insn, 164 BPF_ATOMIC_OP(BPF_B, BPF_STORE_REL, BPF_REG_2, BPF_REG_0, 0)) 165 : __clobber_all); 166 } 167 168 SEC("flow_dissector") 169 __description("store-release to flow_keys pointer") 170 __failure __msg("BPF_ATOMIC stores into R2 flow_keys is not allowed") 171 __naked void store_release_to_flow_keys_pointer(void) 172 { 173 asm volatile ( 174 "w0 = 0;" 175 "r2 = *(u64 *)(r1 + %[__sk_buff_flow_keys]);" 176 ".8byte %[store_release_insn];" // store_release((u8 *)(r2 + 0), w0); 177 "exit;" 178 : 179 : __imm_const(__sk_buff_flow_keys, 180 offsetof(struct __sk_buff, flow_keys)), 181 __imm_insn(store_release_insn, 182 BPF_ATOMIC_OP(BPF_B, BPF_STORE_REL, BPF_REG_2, BPF_REG_0, 0)) 183 : __clobber_all); 184 } 185 186 SEC("sk_reuseport") 187 __description("store-release to sock pointer") 188 __failure __msg("BPF_ATOMIC stores into R2 sock is not allowed") 189 __naked void store_release_to_sock_pointer(void) 190 { 191 asm volatile ( 192 "w0 = 0;" 193 "r2 = *(u64 *)(r1 + %[sk_reuseport_md_sk]);" 194 ".8byte %[store_release_insn];" // store_release((u8 *)(r2 + 0), w0); 195 "exit;" 196 : 197 : __imm_const(sk_reuseport_md_sk, offsetof(struct sk_reuseport_md, sk)), 198 __imm_insn(store_release_insn, 199 BPF_ATOMIC_OP(BPF_B, BPF_STORE_REL, BPF_REG_2, BPF_REG_0, 0)) 200 : __clobber_all); 201 } 202 203 SEC("socket") 204 __description("store-release, leak pointer to stack") 205 __success __success_unpriv __retval(0) 206 __naked void store_release_leak_pointer_to_stack(void) 207 { 208 asm volatile ( 209 ".8byte %[store_release_insn];" // store_release((u64 *)(r10 - 8), r1); 210 "r0 = 0;" 211 "exit;" 212 : 213 : __imm_insn(store_release_insn, 214 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_10, BPF_REG_1, -8)) 215 : __clobber_all); 216 } 217 218 struct { 219 __uint(type, BPF_MAP_TYPE_HASH); 220 __uint(max_entries, 1); 221 __type(key, long long); 222 __type(value, long long); 223 } map_hash_8b SEC(".maps"); 224 225 SEC("socket") 226 __description("store-release, leak pointer to map") 227 __success __retval(0) 228 __failure_unpriv __msg_unpriv("R6 leaks addr into map") 229 __naked void store_release_leak_pointer_to_map(void) 230 { 231 asm volatile ( 232 "r6 = r1;" 233 "r1 = %[map_hash_8b] ll;" 234 "r2 = 0;" 235 "*(u64 *)(r10 - 8) = r2;" 236 "r2 = r10;" 237 "r2 += -8;" 238 "call %[bpf_map_lookup_elem];" 239 "if r0 == 0 goto l0_%=;" 240 ".8byte %[store_release_insn];" // store_release((u64 *)(r0 + 0), r6); 241 "l0_%=:" 242 "r0 = 0;" 243 "exit;" 244 : 245 : __imm_addr(map_hash_8b), 246 __imm(bpf_map_lookup_elem), 247 __imm_insn(store_release_insn, 248 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_0, BPF_REG_6, 0)) 249 : __clobber_all); 250 } 251 252 #else 253 254 SEC("socket") 255 __description("Clang version < 18, ENABLE_ATOMICS_TESTS not defined, and/or JIT doesn't support store-release, use a dummy test") 256 __success 257 int dummy_test(void) 258 { 259 return 0; 260 } 261 262 #endif 263 264 char _license[] SEC("license") = "GPL"; 265