1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Converted from tools/testing/selftests/bpf/verifier/lwt.c */ |
3 | |
4 | #include <linux/bpf.h> |
5 | #include <bpf/bpf_helpers.h> |
6 | #include "bpf_misc.h" |
7 | |
8 | SEC("lwt_in" ) |
9 | __description("invalid direct packet write for LWT_IN" ) |
10 | __failure __msg("cannot write into packet" ) |
11 | __naked void packet_write_for_lwt_in(void) |
12 | { |
13 | asm volatile (" \ |
14 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
15 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
16 | r0 = r2; \ |
17 | r0 += 8; \ |
18 | if r0 > r3 goto l0_%=; \ |
19 | *(u8*)(r2 + 0) = r2; \ |
20 | l0_%=: r0 = 0; \ |
21 | exit; \ |
22 | " : |
23 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
24 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
25 | : __clobber_all); |
26 | } |
27 | |
28 | SEC("lwt_out" ) |
29 | __description("invalid direct packet write for LWT_OUT" ) |
30 | __failure __msg("cannot write into packet" ) |
31 | __naked void packet_write_for_lwt_out(void) |
32 | { |
33 | asm volatile (" \ |
34 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
35 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
36 | r0 = r2; \ |
37 | r0 += 8; \ |
38 | if r0 > r3 goto l0_%=; \ |
39 | *(u8*)(r2 + 0) = r2; \ |
40 | l0_%=: r0 = 0; \ |
41 | exit; \ |
42 | " : |
43 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
44 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
45 | : __clobber_all); |
46 | } |
47 | |
48 | SEC("lwt_xmit" ) |
49 | __description("direct packet write for LWT_XMIT" ) |
50 | __success __retval(0) |
51 | __naked void packet_write_for_lwt_xmit(void) |
52 | { |
53 | asm volatile (" \ |
54 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
55 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
56 | r0 = r2; \ |
57 | r0 += 8; \ |
58 | if r0 > r3 goto l0_%=; \ |
59 | *(u8*)(r2 + 0) = r2; \ |
60 | l0_%=: r0 = 0; \ |
61 | exit; \ |
62 | " : |
63 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
64 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
65 | : __clobber_all); |
66 | } |
67 | |
68 | SEC("lwt_in" ) |
69 | __description("direct packet read for LWT_IN" ) |
70 | __success __retval(0) |
71 | __naked void packet_read_for_lwt_in(void) |
72 | { |
73 | asm volatile (" \ |
74 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
75 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
76 | r0 = r2; \ |
77 | r0 += 8; \ |
78 | if r0 > r3 goto l0_%=; \ |
79 | r0 = *(u8*)(r2 + 0); \ |
80 | l0_%=: r0 = 0; \ |
81 | exit; \ |
82 | " : |
83 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
84 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
85 | : __clobber_all); |
86 | } |
87 | |
88 | SEC("lwt_out" ) |
89 | __description("direct packet read for LWT_OUT" ) |
90 | __success __retval(0) |
91 | __naked void packet_read_for_lwt_out(void) |
92 | { |
93 | asm volatile (" \ |
94 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
95 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
96 | r0 = r2; \ |
97 | r0 += 8; \ |
98 | if r0 > r3 goto l0_%=; \ |
99 | r0 = *(u8*)(r2 + 0); \ |
100 | l0_%=: r0 = 0; \ |
101 | exit; \ |
102 | " : |
103 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
104 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
105 | : __clobber_all); |
106 | } |
107 | |
108 | SEC("lwt_xmit" ) |
109 | __description("direct packet read for LWT_XMIT" ) |
110 | __success __retval(0) |
111 | __naked void packet_read_for_lwt_xmit(void) |
112 | { |
113 | asm volatile (" \ |
114 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
115 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
116 | r0 = r2; \ |
117 | r0 += 8; \ |
118 | if r0 > r3 goto l0_%=; \ |
119 | r0 = *(u8*)(r2 + 0); \ |
120 | l0_%=: r0 = 0; \ |
121 | exit; \ |
122 | " : |
123 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
124 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
125 | : __clobber_all); |
126 | } |
127 | |
128 | SEC("lwt_xmit" ) |
129 | __description("overlapping checks for direct packet access" ) |
130 | __success __retval(0) |
131 | __naked void checks_for_direct_packet_access(void) |
132 | { |
133 | asm volatile (" \ |
134 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
135 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
136 | r0 = r2; \ |
137 | r0 += 8; \ |
138 | if r0 > r3 goto l0_%=; \ |
139 | r1 = r2; \ |
140 | r1 += 6; \ |
141 | if r1 > r3 goto l0_%=; \ |
142 | r0 = *(u16*)(r2 + 6); \ |
143 | l0_%=: r0 = 0; \ |
144 | exit; \ |
145 | " : |
146 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
147 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
148 | : __clobber_all); |
149 | } |
150 | |
151 | SEC("lwt_xmit" ) |
152 | __description("make headroom for LWT_XMIT" ) |
153 | __success __retval(0) |
154 | __naked void make_headroom_for_lwt_xmit(void) |
155 | { |
156 | asm volatile (" \ |
157 | r6 = r1; \ |
158 | r2 = 34; \ |
159 | r3 = 0; \ |
160 | call %[bpf_skb_change_head]; \ |
161 | /* split for s390 to succeed */ \ |
162 | r1 = r6; \ |
163 | r2 = 42; \ |
164 | r3 = 0; \ |
165 | call %[bpf_skb_change_head]; \ |
166 | r0 = 0; \ |
167 | exit; \ |
168 | " : |
169 | : __imm(bpf_skb_change_head) |
170 | : __clobber_all); |
171 | } |
172 | |
173 | SEC("socket" ) |
174 | __description("invalid access of tc_classid for LWT_IN" ) |
175 | __failure __msg("invalid bpf_context access" ) |
176 | __failure_unpriv |
177 | __naked void tc_classid_for_lwt_in(void) |
178 | { |
179 | asm volatile (" \ |
180 | r0 = *(u32*)(r1 + %[__sk_buff_tc_classid]); \ |
181 | exit; \ |
182 | " : |
183 | : __imm_const(__sk_buff_tc_classid, offsetof(struct __sk_buff, tc_classid)) |
184 | : __clobber_all); |
185 | } |
186 | |
187 | SEC("socket" ) |
188 | __description("invalid access of tc_classid for LWT_OUT" ) |
189 | __failure __msg("invalid bpf_context access" ) |
190 | __failure_unpriv |
191 | __naked void tc_classid_for_lwt_out(void) |
192 | { |
193 | asm volatile (" \ |
194 | r0 = *(u32*)(r1 + %[__sk_buff_tc_classid]); \ |
195 | exit; \ |
196 | " : |
197 | : __imm_const(__sk_buff_tc_classid, offsetof(struct __sk_buff, tc_classid)) |
198 | : __clobber_all); |
199 | } |
200 | |
201 | SEC("socket" ) |
202 | __description("invalid access of tc_classid for LWT_XMIT" ) |
203 | __failure __msg("invalid bpf_context access" ) |
204 | __failure_unpriv |
205 | __naked void tc_classid_for_lwt_xmit(void) |
206 | { |
207 | asm volatile (" \ |
208 | r0 = *(u32*)(r1 + %[__sk_buff_tc_classid]); \ |
209 | exit; \ |
210 | " : |
211 | : __imm_const(__sk_buff_tc_classid, offsetof(struct __sk_buff, tc_classid)) |
212 | : __clobber_all); |
213 | } |
214 | |
215 | SEC("lwt_in" ) |
216 | __description("check skb->tc_classid half load not permitted for lwt prog" ) |
217 | __failure __msg("invalid bpf_context access" ) |
218 | __naked void not_permitted_for_lwt_prog(void) |
219 | { |
220 | asm volatile ( |
221 | "r0 = 0;" |
222 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
223 | "r0 = *(u16*)(r1 + %[__sk_buff_tc_classid]);" |
224 | #else |
225 | "r0 = *(u16*)(r1 + %[__imm_0]);" |
226 | #endif |
227 | "exit;" |
228 | : |
229 | : __imm_const(__imm_0, offsetof(struct __sk_buff, tc_classid) + 2), |
230 | __imm_const(__sk_buff_tc_classid, offsetof(struct __sk_buff, tc_classid)) |
231 | : __clobber_all); |
232 | } |
233 | |
234 | char _license[] SEC("license" ) = "GPL" ; |
235 | |