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("load-acquire, 8-bit")
13 __success __success_unpriv __retval(0x12)
load_acquire_8(void)14 __naked void load_acquire_8(void)
15 {
16 asm volatile (
17 "w1 = 0x12;"
18 "*(u8 *)(r10 - 1) = w1;"
19 ".8byte %[load_acquire_insn];" // w0 = load_acquire((u8 *)(r10 - 1));
20 "exit;"
21 :
22 : __imm_insn(load_acquire_insn,
23 BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -1))
24 : __clobber_all);
25 }
26
27 SEC("socket")
28 __description("load-acquire, 16-bit")
29 __success __success_unpriv __retval(0x1234)
load_acquire_16(void)30 __naked void load_acquire_16(void)
31 {
32 asm volatile (
33 "w1 = 0x1234;"
34 "*(u16 *)(r10 - 2) = w1;"
35 ".8byte %[load_acquire_insn];" // w0 = load_acquire((u16 *)(r10 - 2));
36 "exit;"
37 :
38 : __imm_insn(load_acquire_insn,
39 BPF_ATOMIC_OP(BPF_H, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -2))
40 : __clobber_all);
41 }
42
43 SEC("socket")
44 __description("load-acquire, 32-bit")
45 __success __success_unpriv __retval(0x12345678)
load_acquire_32(void)46 __naked void load_acquire_32(void)
47 {
48 asm volatile (
49 "w1 = 0x12345678;"
50 "*(u32 *)(r10 - 4) = w1;"
51 ".8byte %[load_acquire_insn];" // w0 = load_acquire((u32 *)(r10 - 4));
52 "exit;"
53 :
54 : __imm_insn(load_acquire_insn,
55 BPF_ATOMIC_OP(BPF_W, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -4))
56 : __clobber_all);
57 }
58
59 SEC("socket")
60 __description("load-acquire, 64-bit")
61 __success __success_unpriv __retval(0x1234567890abcdef)
load_acquire_64(void)62 __naked void load_acquire_64(void)
63 {
64 asm volatile (
65 "r1 = 0x1234567890abcdef ll;"
66 "*(u64 *)(r10 - 8) = r1;"
67 ".8byte %[load_acquire_insn];" // r0 = load_acquire((u64 *)(r10 - 8));
68 "exit;"
69 :
70 : __imm_insn(load_acquire_insn,
71 BPF_ATOMIC_OP(BPF_DW, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -8))
72 : __clobber_all);
73 }
74
75 SEC("socket")
76 __description("load-acquire with uninitialized src_reg")
77 __failure __failure_unpriv __msg("R2 !read_ok")
load_acquire_with_uninitialized_src_reg(void)78 __naked void load_acquire_with_uninitialized_src_reg(void)
79 {
80 asm volatile (
81 ".8byte %[load_acquire_insn];" // r0 = load_acquire((u64 *)(r2 + 0));
82 "exit;"
83 :
84 : __imm_insn(load_acquire_insn,
85 BPF_ATOMIC_OP(BPF_DW, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_2, 0))
86 : __clobber_all);
87 }
88
89 SEC("socket")
90 __description("load-acquire with non-pointer src_reg")
91 __failure __failure_unpriv __msg("R1 invalid mem access 'scalar'")
load_acquire_with_non_pointer_src_reg(void)92 __naked void load_acquire_with_non_pointer_src_reg(void)
93 {
94 asm volatile (
95 "r1 = 0;"
96 ".8byte %[load_acquire_insn];" // r0 = load_acquire((u64 *)(r1 + 0));
97 "exit;"
98 :
99 : __imm_insn(load_acquire_insn,
100 BPF_ATOMIC_OP(BPF_DW, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_1, 0))
101 : __clobber_all);
102 }
103
104 SEC("socket")
105 __description("misaligned load-acquire")
106 __failure __failure_unpriv __msg("misaligned stack access off")
__flag(BPF_F_ANY_ALIGNMENT)107 __flag(BPF_F_ANY_ALIGNMENT)
108 __naked void load_acquire_misaligned(void)
109 {
110 asm volatile (
111 "r1 = 0;"
112 "*(u64 *)(r10 - 8) = r1;"
113 ".8byte %[load_acquire_insn];" // w0 = load_acquire((u32 *)(r10 - 5));
114 "exit;"
115 :
116 : __imm_insn(load_acquire_insn,
117 BPF_ATOMIC_OP(BPF_W, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -5))
118 : __clobber_all);
119 }
120
121 SEC("socket")
122 __description("load-acquire from ctx pointer")
123 __failure __failure_unpriv __msg("BPF_ATOMIC loads from R1 ctx is not allowed")
load_acquire_from_ctx_pointer(void)124 __naked void load_acquire_from_ctx_pointer(void)
125 {
126 asm volatile (
127 ".8byte %[load_acquire_insn];" // w0 = load_acquire((u8 *)(r1 + 0));
128 "exit;"
129 :
130 : __imm_insn(load_acquire_insn,
131 BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_1, 0))
132 : __clobber_all);
133 }
134
135 SEC("xdp")
136 __description("load-acquire from pkt pointer")
137 __failure __msg("BPF_ATOMIC loads from R2 pkt is not allowed")
load_acquire_from_pkt_pointer(void)138 __naked void load_acquire_from_pkt_pointer(void)
139 {
140 asm volatile (
141 "r2 = *(u32 *)(r1 + %[xdp_md_data]);"
142 "r3 = *(u32 *)(r1 + %[xdp_md_data_end]);"
143 "r1 = r2;"
144 "r1 += 8;"
145 "if r1 >= r3 goto l0_%=;"
146 ".8byte %[load_acquire_insn];" // w0 = load_acquire((u8 *)(r2 + 0));
147 "l0_%=: r0 = 0;"
148 "exit;"
149 :
150 : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
151 __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end)),
152 __imm_insn(load_acquire_insn,
153 BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_2, 0))
154 : __clobber_all);
155 }
156
157 SEC("flow_dissector")
158 __description("load-acquire from flow_keys pointer")
159 __failure __msg("BPF_ATOMIC loads from R2 flow_keys is not allowed")
load_acquire_from_flow_keys_pointer(void)160 __naked void load_acquire_from_flow_keys_pointer(void)
161 {
162 asm volatile (
163 "r2 = *(u64 *)(r1 + %[__sk_buff_flow_keys]);"
164 ".8byte %[load_acquire_insn];" // w0 = load_acquire((u8 *)(r2 + 0));
165 "exit;"
166 :
167 : __imm_const(__sk_buff_flow_keys,
168 offsetof(struct __sk_buff, flow_keys)),
169 __imm_insn(load_acquire_insn,
170 BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_2, 0))
171 : __clobber_all);
172 }
173
174 SEC("sk_reuseport")
175 __description("load-acquire from sock pointer")
176 __failure __msg("BPF_ATOMIC loads from R2 sock is not allowed")
load_acquire_from_sock_pointer(void)177 __naked void load_acquire_from_sock_pointer(void)
178 {
179 asm volatile (
180 "r2 = *(u64 *)(r1 + %[sk_reuseport_md_sk]);"
181 // w0 = load_acquire((u8 *)(r2 + offsetof(struct bpf_sock, family)));
182 ".8byte %[load_acquire_insn];"
183 "exit;"
184 :
185 : __imm_const(sk_reuseport_md_sk, offsetof(struct sk_reuseport_md, sk)),
186 __imm_insn(load_acquire_insn,
187 BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_2,
188 offsetof(struct bpf_sock, family)))
189 : __clobber_all);
190 }
191
192 SEC("socket")
193 __description("load-acquire with invalid register R15")
194 __failure __failure_unpriv __msg("R15 is invalid")
load_acquire_with_invalid_reg(void)195 __naked void load_acquire_with_invalid_reg(void)
196 {
197 asm volatile (
198 ".8byte %[load_acquire_insn];" // r0 = load_acquire((u64 *)(r15 + 0));
199 "exit;"
200 :
201 : __imm_insn(load_acquire_insn,
202 BPF_ATOMIC_OP(BPF_DW, BPF_LOAD_ACQ, BPF_REG_0, 15 /* invalid reg */, 0))
203 : __clobber_all);
204 }
205
206 #else /* CAN_USE_LOAD_ACQ_STORE_REL */
207
208 SEC("socket")
209 __description("Clang version < 18, ENABLE_ATOMICS_TESTS not defined, and/or JIT doesn't support load-acquire, use a dummy test")
210 __success
dummy_test(void)211 int dummy_test(void)
212 {
213 return 0;
214 }
215
216 #endif /* CAN_USE_LOAD_ACQ_STORE_REL */
217
218 char _license[] SEC("license") = "GPL";
219