1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2019 Facebook |
3 | |
4 | #include <fcntl.h> |
5 | #include <stdint.h> |
6 | #include <stdio.h> |
7 | #include <stdlib.h> |
8 | #include <string.h> |
9 | #include <unistd.h> |
10 | |
11 | #include <linux/filter.h> |
12 | |
13 | #include <bpf/bpf.h> |
14 | #include <bpf/libbpf.h> |
15 | |
16 | #include <bpf/bpf_endian.h> |
17 | #include "bpf_util.h" |
18 | #include "cgroup_helpers.h" |
19 | #include "testing_helpers.h" |
20 | |
21 | #define CG_PATH "/foo" |
22 | #define MAX_INSNS 512 |
23 | #define FIXUP_SYSCTL_VALUE 0 |
24 | |
25 | char bpf_log_buf[BPF_LOG_BUF_SIZE]; |
26 | |
27 | struct sysctl_test { |
28 | const char *descr; |
29 | size_t fixup_value_insn; |
30 | struct bpf_insn insns[MAX_INSNS]; |
31 | const char *prog_file; |
32 | enum bpf_attach_type attach_type; |
33 | const char *sysctl; |
34 | int open_flags; |
35 | int seek; |
36 | const char *newval; |
37 | const char *oldval; |
38 | enum { |
39 | LOAD_REJECT, |
40 | ATTACH_REJECT, |
41 | OP_EPERM, |
42 | SUCCESS, |
43 | } result; |
44 | }; |
45 | |
46 | static struct sysctl_test tests[] = { |
47 | { |
48 | .descr = "sysctl wrong attach_type" , |
49 | .insns = { |
50 | BPF_MOV64_IMM(BPF_REG_0, 1), |
51 | BPF_EXIT_INSN(), |
52 | }, |
53 | .attach_type = 0, |
54 | .sysctl = "kernel/ostype" , |
55 | .open_flags = O_RDONLY, |
56 | .result = ATTACH_REJECT, |
57 | }, |
58 | { |
59 | .descr = "sysctl:read allow all" , |
60 | .insns = { |
61 | BPF_MOV64_IMM(BPF_REG_0, 1), |
62 | BPF_EXIT_INSN(), |
63 | }, |
64 | .attach_type = BPF_CGROUP_SYSCTL, |
65 | .sysctl = "kernel/ostype" , |
66 | .open_flags = O_RDONLY, |
67 | .result = SUCCESS, |
68 | }, |
69 | { |
70 | .descr = "sysctl:read deny all" , |
71 | .insns = { |
72 | BPF_MOV64_IMM(BPF_REG_0, 0), |
73 | BPF_EXIT_INSN(), |
74 | }, |
75 | .attach_type = BPF_CGROUP_SYSCTL, |
76 | .sysctl = "kernel/ostype" , |
77 | .open_flags = O_RDONLY, |
78 | .result = OP_EPERM, |
79 | }, |
80 | { |
81 | .descr = "ctx:write sysctl:read read ok" , |
82 | .insns = { |
83 | /* If (write) */ |
84 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, |
85 | offsetof(struct bpf_sysctl, write)), |
86 | BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 1, 2), |
87 | |
88 | /* return DENY; */ |
89 | BPF_MOV64_IMM(BPF_REG_0, 0), |
90 | BPF_JMP_A(1), |
91 | |
92 | /* else return ALLOW; */ |
93 | BPF_MOV64_IMM(BPF_REG_0, 1), |
94 | BPF_EXIT_INSN(), |
95 | }, |
96 | .attach_type = BPF_CGROUP_SYSCTL, |
97 | .sysctl = "kernel/ostype" , |
98 | .open_flags = O_RDONLY, |
99 | .result = SUCCESS, |
100 | }, |
101 | { |
102 | .descr = "ctx:write sysctl:write read ok" , |
103 | .insns = { |
104 | /* If (write) */ |
105 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, |
106 | offsetof(struct bpf_sysctl, write)), |
107 | BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 1, 2), |
108 | |
109 | /* return DENY; */ |
110 | BPF_MOV64_IMM(BPF_REG_0, 0), |
111 | BPF_JMP_A(1), |
112 | |
113 | /* else return ALLOW; */ |
114 | BPF_MOV64_IMM(BPF_REG_0, 1), |
115 | BPF_EXIT_INSN(), |
116 | }, |
117 | .attach_type = BPF_CGROUP_SYSCTL, |
118 | .sysctl = "kernel/domainname" , |
119 | .open_flags = O_WRONLY, |
120 | .newval = "(none)" , /* same as default, should fail anyway */ |
121 | .result = OP_EPERM, |
122 | }, |
123 | { |
124 | .descr = "ctx:write sysctl:write read ok narrow" , |
125 | .insns = { |
126 | /* u64 w = (u16)write & 1; */ |
127 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
128 | BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_1, |
129 | offsetof(struct bpf_sysctl, write)), |
130 | #else |
131 | BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_1, |
132 | offsetof(struct bpf_sysctl, write) + 2), |
133 | #endif |
134 | BPF_ALU64_IMM(BPF_AND, BPF_REG_7, 1), |
135 | /* return 1 - w; */ |
136 | BPF_MOV64_IMM(BPF_REG_0, 1), |
137 | BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_7), |
138 | BPF_EXIT_INSN(), |
139 | }, |
140 | .attach_type = BPF_CGROUP_SYSCTL, |
141 | .sysctl = "kernel/domainname" , |
142 | .open_flags = O_WRONLY, |
143 | .newval = "(none)" , /* same as default, should fail anyway */ |
144 | .result = OP_EPERM, |
145 | }, |
146 | { |
147 | .descr = "ctx:write sysctl:read write reject" , |
148 | .insns = { |
149 | /* write = X */ |
150 | BPF_MOV64_IMM(BPF_REG_0, 0), |
151 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, |
152 | offsetof(struct bpf_sysctl, write)), |
153 | BPF_MOV64_IMM(BPF_REG_0, 1), |
154 | BPF_EXIT_INSN(), |
155 | }, |
156 | .attach_type = BPF_CGROUP_SYSCTL, |
157 | .sysctl = "kernel/ostype" , |
158 | .open_flags = O_RDONLY, |
159 | .result = LOAD_REJECT, |
160 | }, |
161 | { |
162 | .descr = "ctx:file_pos sysctl:read read ok" , |
163 | .insns = { |
164 | /* If (file_pos == X) */ |
165 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, |
166 | offsetof(struct bpf_sysctl, file_pos)), |
167 | BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 3, 2), |
168 | |
169 | /* return ALLOW; */ |
170 | BPF_MOV64_IMM(BPF_REG_0, 1), |
171 | BPF_JMP_A(1), |
172 | |
173 | /* else return DENY; */ |
174 | BPF_MOV64_IMM(BPF_REG_0, 0), |
175 | BPF_EXIT_INSN(), |
176 | }, |
177 | .attach_type = BPF_CGROUP_SYSCTL, |
178 | .sysctl = "kernel/ostype" , |
179 | .open_flags = O_RDONLY, |
180 | .seek = 3, |
181 | .result = SUCCESS, |
182 | }, |
183 | { |
184 | .descr = "ctx:file_pos sysctl:read read ok narrow" , |
185 | .insns = { |
186 | /* If (file_pos == X) */ |
187 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
188 | BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_1, |
189 | offsetof(struct bpf_sysctl, file_pos)), |
190 | #else |
191 | BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_1, |
192 | offsetof(struct bpf_sysctl, file_pos) + 3), |
193 | #endif |
194 | BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 4, 2), |
195 | |
196 | /* return ALLOW; */ |
197 | BPF_MOV64_IMM(BPF_REG_0, 1), |
198 | BPF_JMP_A(1), |
199 | |
200 | /* else return DENY; */ |
201 | BPF_MOV64_IMM(BPF_REG_0, 0), |
202 | BPF_EXIT_INSN(), |
203 | }, |
204 | .attach_type = BPF_CGROUP_SYSCTL, |
205 | .sysctl = "kernel/ostype" , |
206 | .open_flags = O_RDONLY, |
207 | .seek = 4, |
208 | .result = SUCCESS, |
209 | }, |
210 | { |
211 | .descr = "ctx:file_pos sysctl:read write ok" , |
212 | .insns = { |
213 | /* file_pos = X */ |
214 | BPF_MOV64_IMM(BPF_REG_0, 2), |
215 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, |
216 | offsetof(struct bpf_sysctl, file_pos)), |
217 | BPF_MOV64_IMM(BPF_REG_0, 1), |
218 | BPF_EXIT_INSN(), |
219 | }, |
220 | .attach_type = BPF_CGROUP_SYSCTL, |
221 | .sysctl = "kernel/ostype" , |
222 | .open_flags = O_RDONLY, |
223 | .oldval = "nux\n" , |
224 | .result = SUCCESS, |
225 | }, |
226 | { |
227 | .descr = "sysctl_get_name sysctl_value:base ok" , |
228 | .insns = { |
229 | /* sysctl_get_name arg2 (buf) */ |
230 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
231 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
232 | BPF_MOV64_IMM(BPF_REG_0, 0), |
233 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
234 | |
235 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
236 | |
237 | /* sysctl_get_name arg3 (buf_len) */ |
238 | BPF_MOV64_IMM(BPF_REG_3, 8), |
239 | |
240 | /* sysctl_get_name arg4 (flags) */ |
241 | BPF_MOV64_IMM(BPF_REG_4, BPF_F_SYSCTL_BASE_NAME), |
242 | |
243 | /* sysctl_get_name(ctx, buf, buf_len, flags) */ |
244 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_name), |
245 | |
246 | /* if (ret == expected && */ |
247 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, sizeof("tcp_mem" ) - 1, 6), |
248 | /* buf == "tcp_mem\0") */ |
249 | BPF_LD_IMM64(BPF_REG_8, |
250 | bpf_be64_to_cpu(0x7463705f6d656d00ULL)), |
251 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
252 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
253 | |
254 | /* return ALLOW; */ |
255 | BPF_MOV64_IMM(BPF_REG_0, 1), |
256 | BPF_JMP_A(1), |
257 | |
258 | /* else return DENY; */ |
259 | BPF_MOV64_IMM(BPF_REG_0, 0), |
260 | BPF_EXIT_INSN(), |
261 | }, |
262 | .attach_type = BPF_CGROUP_SYSCTL, |
263 | .sysctl = "net/ipv4/tcp_mem" , |
264 | .open_flags = O_RDONLY, |
265 | .result = SUCCESS, |
266 | }, |
267 | { |
268 | .descr = "sysctl_get_name sysctl_value:base E2BIG truncated" , |
269 | .insns = { |
270 | /* sysctl_get_name arg2 (buf) */ |
271 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
272 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
273 | BPF_MOV64_IMM(BPF_REG_0, 0), |
274 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
275 | |
276 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
277 | |
278 | /* sysctl_get_name arg3 (buf_len) too small */ |
279 | BPF_MOV64_IMM(BPF_REG_3, 7), |
280 | |
281 | /* sysctl_get_name arg4 (flags) */ |
282 | BPF_MOV64_IMM(BPF_REG_4, BPF_F_SYSCTL_BASE_NAME), |
283 | |
284 | /* sysctl_get_name(ctx, buf, buf_len, flags) */ |
285 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_name), |
286 | |
287 | /* if (ret == expected && */ |
288 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -E2BIG, 6), |
289 | |
290 | /* buf[0:7] == "tcp_me\0") */ |
291 | BPF_LD_IMM64(BPF_REG_8, |
292 | bpf_be64_to_cpu(0x7463705f6d650000ULL)), |
293 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
294 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
295 | |
296 | /* return ALLOW; */ |
297 | BPF_MOV64_IMM(BPF_REG_0, 1), |
298 | BPF_JMP_A(1), |
299 | |
300 | /* else return DENY; */ |
301 | BPF_MOV64_IMM(BPF_REG_0, 0), |
302 | BPF_EXIT_INSN(), |
303 | }, |
304 | .attach_type = BPF_CGROUP_SYSCTL, |
305 | .sysctl = "net/ipv4/tcp_mem" , |
306 | .open_flags = O_RDONLY, |
307 | .result = SUCCESS, |
308 | }, |
309 | { |
310 | .descr = "sysctl_get_name sysctl:full ok" , |
311 | .insns = { |
312 | /* sysctl_get_name arg2 (buf) */ |
313 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
314 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -24), |
315 | BPF_MOV64_IMM(BPF_REG_0, 0), |
316 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
317 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 8), |
318 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 16), |
319 | |
320 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
321 | |
322 | /* sysctl_get_name arg3 (buf_len) */ |
323 | BPF_MOV64_IMM(BPF_REG_3, 17), |
324 | |
325 | /* sysctl_get_name arg4 (flags) */ |
326 | BPF_MOV64_IMM(BPF_REG_4, 0), |
327 | |
328 | /* sysctl_get_name(ctx, buf, buf_len, flags) */ |
329 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_name), |
330 | |
331 | /* if (ret == expected && */ |
332 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 16, 14), |
333 | |
334 | /* buf[0:8] == "net/ipv4" && */ |
335 | BPF_LD_IMM64(BPF_REG_8, |
336 | bpf_be64_to_cpu(0x6e65742f69707634ULL)), |
337 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
338 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 10), |
339 | |
340 | /* buf[8:16] == "/tcp_mem" && */ |
341 | BPF_LD_IMM64(BPF_REG_8, |
342 | bpf_be64_to_cpu(0x2f7463705f6d656dULL)), |
343 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 8), |
344 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 6), |
345 | |
346 | /* buf[16:24] == "\0") */ |
347 | BPF_LD_IMM64(BPF_REG_8, 0x0ULL), |
348 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 16), |
349 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
350 | |
351 | /* return ALLOW; */ |
352 | BPF_MOV64_IMM(BPF_REG_0, 1), |
353 | BPF_JMP_A(1), |
354 | |
355 | /* else return DENY; */ |
356 | BPF_MOV64_IMM(BPF_REG_0, 0), |
357 | BPF_EXIT_INSN(), |
358 | }, |
359 | .attach_type = BPF_CGROUP_SYSCTL, |
360 | .sysctl = "net/ipv4/tcp_mem" , |
361 | .open_flags = O_RDONLY, |
362 | .result = SUCCESS, |
363 | }, |
364 | { |
365 | .descr = "sysctl_get_name sysctl:full E2BIG truncated" , |
366 | .insns = { |
367 | /* sysctl_get_name arg2 (buf) */ |
368 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
369 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -16), |
370 | BPF_MOV64_IMM(BPF_REG_0, 0), |
371 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
372 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 8), |
373 | |
374 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
375 | |
376 | /* sysctl_get_name arg3 (buf_len) */ |
377 | BPF_MOV64_IMM(BPF_REG_3, 16), |
378 | |
379 | /* sysctl_get_name arg4 (flags) */ |
380 | BPF_MOV64_IMM(BPF_REG_4, 0), |
381 | |
382 | /* sysctl_get_name(ctx, buf, buf_len, flags) */ |
383 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_name), |
384 | |
385 | /* if (ret == expected && */ |
386 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -E2BIG, 10), |
387 | |
388 | /* buf[0:8] == "net/ipv4" && */ |
389 | BPF_LD_IMM64(BPF_REG_8, |
390 | bpf_be64_to_cpu(0x6e65742f69707634ULL)), |
391 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
392 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 6), |
393 | |
394 | /* buf[8:16] == "/tcp_me\0") */ |
395 | BPF_LD_IMM64(BPF_REG_8, |
396 | bpf_be64_to_cpu(0x2f7463705f6d6500ULL)), |
397 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 8), |
398 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
399 | |
400 | /* return ALLOW; */ |
401 | BPF_MOV64_IMM(BPF_REG_0, 1), |
402 | BPF_JMP_A(1), |
403 | |
404 | /* else return DENY; */ |
405 | BPF_MOV64_IMM(BPF_REG_0, 0), |
406 | BPF_EXIT_INSN(), |
407 | }, |
408 | .attach_type = BPF_CGROUP_SYSCTL, |
409 | .sysctl = "net/ipv4/tcp_mem" , |
410 | .open_flags = O_RDONLY, |
411 | .result = SUCCESS, |
412 | }, |
413 | { |
414 | .descr = "sysctl_get_name sysctl:full E2BIG truncated small" , |
415 | .insns = { |
416 | /* sysctl_get_name arg2 (buf) */ |
417 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
418 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
419 | BPF_MOV64_IMM(BPF_REG_0, 0), |
420 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
421 | |
422 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
423 | |
424 | /* sysctl_get_name arg3 (buf_len) */ |
425 | BPF_MOV64_IMM(BPF_REG_3, 7), |
426 | |
427 | /* sysctl_get_name arg4 (flags) */ |
428 | BPF_MOV64_IMM(BPF_REG_4, 0), |
429 | |
430 | /* sysctl_get_name(ctx, buf, buf_len, flags) */ |
431 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_name), |
432 | |
433 | /* if (ret == expected && */ |
434 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -E2BIG, 6), |
435 | |
436 | /* buf[0:8] == "net/ip\0") */ |
437 | BPF_LD_IMM64(BPF_REG_8, |
438 | bpf_be64_to_cpu(0x6e65742f69700000ULL)), |
439 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
440 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
441 | |
442 | /* return ALLOW; */ |
443 | BPF_MOV64_IMM(BPF_REG_0, 1), |
444 | BPF_JMP_A(1), |
445 | |
446 | /* else return DENY; */ |
447 | BPF_MOV64_IMM(BPF_REG_0, 0), |
448 | BPF_EXIT_INSN(), |
449 | }, |
450 | .attach_type = BPF_CGROUP_SYSCTL, |
451 | .sysctl = "net/ipv4/tcp_mem" , |
452 | .open_flags = O_RDONLY, |
453 | .result = SUCCESS, |
454 | }, |
455 | { |
456 | .descr = "sysctl_get_current_value sysctl:read ok, gt" , |
457 | .insns = { |
458 | /* sysctl_get_current_value arg2 (buf) */ |
459 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
460 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
461 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
462 | |
463 | /* sysctl_get_current_value arg3 (buf_len) */ |
464 | BPF_MOV64_IMM(BPF_REG_3, 8), |
465 | |
466 | /* sysctl_get_current_value(ctx, buf, buf_len) */ |
467 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_current_value), |
468 | |
469 | /* if (ret == expected && */ |
470 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 6, 6), |
471 | |
472 | /* buf[0:6] == "Linux\n\0") */ |
473 | BPF_LD_IMM64(BPF_REG_8, |
474 | bpf_be64_to_cpu(0x4c696e75780a0000ULL)), |
475 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
476 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
477 | |
478 | /* return ALLOW; */ |
479 | BPF_MOV64_IMM(BPF_REG_0, 1), |
480 | BPF_JMP_A(1), |
481 | |
482 | /* else return DENY; */ |
483 | BPF_MOV64_IMM(BPF_REG_0, 0), |
484 | BPF_EXIT_INSN(), |
485 | }, |
486 | .attach_type = BPF_CGROUP_SYSCTL, |
487 | .sysctl = "kernel/ostype" , |
488 | .open_flags = O_RDONLY, |
489 | .result = SUCCESS, |
490 | }, |
491 | { |
492 | .descr = "sysctl_get_current_value sysctl:read ok, eq" , |
493 | .insns = { |
494 | /* sysctl_get_current_value arg2 (buf) */ |
495 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
496 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
497 | BPF_MOV64_IMM(BPF_REG_0, 0), |
498 | BPF_STX_MEM(BPF_B, BPF_REG_7, BPF_REG_0, 7), |
499 | |
500 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
501 | |
502 | /* sysctl_get_current_value arg3 (buf_len) */ |
503 | BPF_MOV64_IMM(BPF_REG_3, 7), |
504 | |
505 | /* sysctl_get_current_value(ctx, buf, buf_len) */ |
506 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_current_value), |
507 | |
508 | /* if (ret == expected && */ |
509 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 6, 6), |
510 | |
511 | /* buf[0:6] == "Linux\n\0") */ |
512 | BPF_LD_IMM64(BPF_REG_8, |
513 | bpf_be64_to_cpu(0x4c696e75780a0000ULL)), |
514 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
515 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
516 | |
517 | /* return ALLOW; */ |
518 | BPF_MOV64_IMM(BPF_REG_0, 1), |
519 | BPF_JMP_A(1), |
520 | |
521 | /* else return DENY; */ |
522 | BPF_MOV64_IMM(BPF_REG_0, 0), |
523 | BPF_EXIT_INSN(), |
524 | }, |
525 | .attach_type = BPF_CGROUP_SYSCTL, |
526 | .sysctl = "kernel/ostype" , |
527 | .open_flags = O_RDONLY, |
528 | .result = SUCCESS, |
529 | }, |
530 | { |
531 | .descr = "sysctl_get_current_value sysctl:read E2BIG truncated" , |
532 | .insns = { |
533 | /* sysctl_get_current_value arg2 (buf) */ |
534 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
535 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
536 | BPF_MOV64_IMM(BPF_REG_0, 0), |
537 | BPF_STX_MEM(BPF_H, BPF_REG_7, BPF_REG_0, 6), |
538 | |
539 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
540 | |
541 | /* sysctl_get_current_value arg3 (buf_len) */ |
542 | BPF_MOV64_IMM(BPF_REG_3, 6), |
543 | |
544 | /* sysctl_get_current_value(ctx, buf, buf_len) */ |
545 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_current_value), |
546 | |
547 | /* if (ret == expected && */ |
548 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -E2BIG, 6), |
549 | |
550 | /* buf[0:6] == "Linux\0") */ |
551 | BPF_LD_IMM64(BPF_REG_8, |
552 | bpf_be64_to_cpu(0x4c696e7578000000ULL)), |
553 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
554 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
555 | |
556 | /* return ALLOW; */ |
557 | BPF_MOV64_IMM(BPF_REG_0, 1), |
558 | BPF_JMP_A(1), |
559 | |
560 | /* else return DENY; */ |
561 | BPF_MOV64_IMM(BPF_REG_0, 0), |
562 | BPF_EXIT_INSN(), |
563 | }, |
564 | .attach_type = BPF_CGROUP_SYSCTL, |
565 | .sysctl = "kernel/ostype" , |
566 | .open_flags = O_RDONLY, |
567 | .result = SUCCESS, |
568 | }, |
569 | { |
570 | .descr = "sysctl_get_current_value sysctl:read EINVAL" , |
571 | .insns = { |
572 | /* sysctl_get_current_value arg2 (buf) */ |
573 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
574 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
575 | |
576 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
577 | |
578 | /* sysctl_get_current_value arg3 (buf_len) */ |
579 | BPF_MOV64_IMM(BPF_REG_3, 8), |
580 | |
581 | /* sysctl_get_current_value(ctx, buf, buf_len) */ |
582 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_current_value), |
583 | |
584 | /* if (ret == expected && */ |
585 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -EINVAL, 4), |
586 | |
587 | /* buf[0:8] is NUL-filled) */ |
588 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
589 | BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 2), |
590 | |
591 | /* return DENY; */ |
592 | BPF_MOV64_IMM(BPF_REG_0, 0), |
593 | BPF_JMP_A(1), |
594 | |
595 | /* else return ALLOW; */ |
596 | BPF_MOV64_IMM(BPF_REG_0, 1), |
597 | BPF_EXIT_INSN(), |
598 | }, |
599 | .attach_type = BPF_CGROUP_SYSCTL, |
600 | .sysctl = "net/ipv6/conf/lo/stable_secret" , /* -EIO */ |
601 | .open_flags = O_RDONLY, |
602 | .result = OP_EPERM, |
603 | }, |
604 | { |
605 | .descr = "sysctl_get_current_value sysctl:write ok" , |
606 | .fixup_value_insn = 6, |
607 | .insns = { |
608 | /* sysctl_get_current_value arg2 (buf) */ |
609 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
610 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
611 | |
612 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
613 | |
614 | /* sysctl_get_current_value arg3 (buf_len) */ |
615 | BPF_MOV64_IMM(BPF_REG_3, 8), |
616 | |
617 | /* sysctl_get_current_value(ctx, buf, buf_len) */ |
618 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_current_value), |
619 | |
620 | /* if (ret == expected && */ |
621 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 4, 6), |
622 | |
623 | /* buf[0:4] == expected) */ |
624 | BPF_LD_IMM64(BPF_REG_8, FIXUP_SYSCTL_VALUE), |
625 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
626 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
627 | |
628 | /* return DENY; */ |
629 | BPF_MOV64_IMM(BPF_REG_0, 0), |
630 | BPF_JMP_A(1), |
631 | |
632 | /* else return ALLOW; */ |
633 | BPF_MOV64_IMM(BPF_REG_0, 1), |
634 | BPF_EXIT_INSN(), |
635 | }, |
636 | .attach_type = BPF_CGROUP_SYSCTL, |
637 | .sysctl = "net/ipv4/route/mtu_expires" , |
638 | .open_flags = O_WRONLY, |
639 | .newval = "600" , /* same as default, should fail anyway */ |
640 | .result = OP_EPERM, |
641 | }, |
642 | { |
643 | .descr = "sysctl_get_new_value sysctl:read EINVAL" , |
644 | .insns = { |
645 | /* sysctl_get_new_value arg2 (buf) */ |
646 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
647 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
648 | BPF_MOV64_IMM(BPF_REG_0, 0), |
649 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
650 | |
651 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
652 | |
653 | /* sysctl_get_new_value arg3 (buf_len) */ |
654 | BPF_MOV64_IMM(BPF_REG_3, 8), |
655 | |
656 | /* sysctl_get_new_value(ctx, buf, buf_len) */ |
657 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_new_value), |
658 | |
659 | /* if (ret == expected) */ |
660 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -EINVAL, 2), |
661 | |
662 | /* return ALLOW; */ |
663 | BPF_MOV64_IMM(BPF_REG_0, 1), |
664 | BPF_JMP_A(1), |
665 | |
666 | /* else return DENY; */ |
667 | BPF_MOV64_IMM(BPF_REG_0, 0), |
668 | BPF_EXIT_INSN(), |
669 | }, |
670 | .attach_type = BPF_CGROUP_SYSCTL, |
671 | .sysctl = "net/ipv4/tcp_mem" , |
672 | .open_flags = O_RDONLY, |
673 | .result = SUCCESS, |
674 | }, |
675 | { |
676 | .descr = "sysctl_get_new_value sysctl:write ok" , |
677 | .insns = { |
678 | /* sysctl_get_new_value arg2 (buf) */ |
679 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
680 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
681 | |
682 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
683 | |
684 | /* sysctl_get_new_value arg3 (buf_len) */ |
685 | BPF_MOV64_IMM(BPF_REG_3, 4), |
686 | |
687 | /* sysctl_get_new_value(ctx, buf, buf_len) */ |
688 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_new_value), |
689 | |
690 | /* if (ret == expected && */ |
691 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 3, 4), |
692 | |
693 | /* buf[0:4] == "606\0") */ |
694 | BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_7, 0), |
695 | BPF_JMP_IMM(BPF_JNE, BPF_REG_9, |
696 | bpf_ntohl(0x36303600), 2), |
697 | |
698 | /* return DENY; */ |
699 | BPF_MOV64_IMM(BPF_REG_0, 0), |
700 | BPF_JMP_A(1), |
701 | |
702 | /* else return ALLOW; */ |
703 | BPF_MOV64_IMM(BPF_REG_0, 1), |
704 | BPF_EXIT_INSN(), |
705 | }, |
706 | .attach_type = BPF_CGROUP_SYSCTL, |
707 | .sysctl = "net/ipv4/route/mtu_expires" , |
708 | .open_flags = O_WRONLY, |
709 | .newval = "606" , |
710 | .result = OP_EPERM, |
711 | }, |
712 | { |
713 | .descr = "sysctl_get_new_value sysctl:write ok long" , |
714 | .insns = { |
715 | /* sysctl_get_new_value arg2 (buf) */ |
716 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
717 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -24), |
718 | |
719 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
720 | |
721 | /* sysctl_get_new_value arg3 (buf_len) */ |
722 | BPF_MOV64_IMM(BPF_REG_3, 24), |
723 | |
724 | /* sysctl_get_new_value(ctx, buf, buf_len) */ |
725 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_new_value), |
726 | |
727 | /* if (ret == expected && */ |
728 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 23, 14), |
729 | |
730 | /* buf[0:8] == "3000000 " && */ |
731 | BPF_LD_IMM64(BPF_REG_8, |
732 | bpf_be64_to_cpu(0x3330303030303020ULL)), |
733 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
734 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 10), |
735 | |
736 | /* buf[8:16] == "4000000 " && */ |
737 | BPF_LD_IMM64(BPF_REG_8, |
738 | bpf_be64_to_cpu(0x3430303030303020ULL)), |
739 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 8), |
740 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 6), |
741 | |
742 | /* buf[16:24] == "6000000\0") */ |
743 | BPF_LD_IMM64(BPF_REG_8, |
744 | bpf_be64_to_cpu(0x3630303030303000ULL)), |
745 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 16), |
746 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
747 | |
748 | /* return DENY; */ |
749 | BPF_MOV64_IMM(BPF_REG_0, 0), |
750 | BPF_JMP_A(1), |
751 | |
752 | /* else return ALLOW; */ |
753 | BPF_MOV64_IMM(BPF_REG_0, 1), |
754 | BPF_EXIT_INSN(), |
755 | }, |
756 | .attach_type = BPF_CGROUP_SYSCTL, |
757 | .sysctl = "net/ipv4/tcp_mem" , |
758 | .open_flags = O_WRONLY, |
759 | .newval = "3000000 4000000 6000000" , |
760 | .result = OP_EPERM, |
761 | }, |
762 | { |
763 | .descr = "sysctl_get_new_value sysctl:write E2BIG" , |
764 | .insns = { |
765 | /* sysctl_get_new_value arg2 (buf) */ |
766 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
767 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
768 | BPF_MOV64_IMM(BPF_REG_0, 0), |
769 | BPF_STX_MEM(BPF_B, BPF_REG_7, BPF_REG_0, 3), |
770 | |
771 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
772 | |
773 | /* sysctl_get_new_value arg3 (buf_len) */ |
774 | BPF_MOV64_IMM(BPF_REG_3, 3), |
775 | |
776 | /* sysctl_get_new_value(ctx, buf, buf_len) */ |
777 | BPF_EMIT_CALL(BPF_FUNC_sysctl_get_new_value), |
778 | |
779 | /* if (ret == expected && */ |
780 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -E2BIG, 4), |
781 | |
782 | /* buf[0:3] == "60\0") */ |
783 | BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_7, 0), |
784 | BPF_JMP_IMM(BPF_JNE, BPF_REG_9, |
785 | bpf_ntohl(0x36300000), 2), |
786 | |
787 | /* return DENY; */ |
788 | BPF_MOV64_IMM(BPF_REG_0, 0), |
789 | BPF_JMP_A(1), |
790 | |
791 | /* else return ALLOW; */ |
792 | BPF_MOV64_IMM(BPF_REG_0, 1), |
793 | BPF_EXIT_INSN(), |
794 | }, |
795 | .attach_type = BPF_CGROUP_SYSCTL, |
796 | .sysctl = "net/ipv4/route/mtu_expires" , |
797 | .open_flags = O_WRONLY, |
798 | .newval = "606" , |
799 | .result = OP_EPERM, |
800 | }, |
801 | { |
802 | .descr = "sysctl_set_new_value sysctl:read EINVAL" , |
803 | .insns = { |
804 | /* sysctl_set_new_value arg2 (buf) */ |
805 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
806 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
807 | BPF_MOV64_IMM(BPF_REG_0, |
808 | bpf_ntohl(0x36303000)), |
809 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
810 | |
811 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
812 | |
813 | /* sysctl_set_new_value arg3 (buf_len) */ |
814 | BPF_MOV64_IMM(BPF_REG_3, 3), |
815 | |
816 | /* sysctl_set_new_value(ctx, buf, buf_len) */ |
817 | BPF_EMIT_CALL(BPF_FUNC_sysctl_set_new_value), |
818 | |
819 | /* if (ret == expected) */ |
820 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -EINVAL, 2), |
821 | |
822 | /* return ALLOW; */ |
823 | BPF_MOV64_IMM(BPF_REG_0, 1), |
824 | BPF_JMP_A(1), |
825 | |
826 | /* else return DENY; */ |
827 | BPF_MOV64_IMM(BPF_REG_0, 0), |
828 | BPF_EXIT_INSN(), |
829 | }, |
830 | .attach_type = BPF_CGROUP_SYSCTL, |
831 | .sysctl = "net/ipv4/route/mtu_expires" , |
832 | .open_flags = O_RDONLY, |
833 | .result = SUCCESS, |
834 | }, |
835 | { |
836 | .descr = "sysctl_set_new_value sysctl:write ok" , |
837 | .fixup_value_insn = 2, |
838 | .insns = { |
839 | /* sysctl_set_new_value arg2 (buf) */ |
840 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
841 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
842 | BPF_LD_IMM64(BPF_REG_0, FIXUP_SYSCTL_VALUE), |
843 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
844 | |
845 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_7), |
846 | |
847 | /* sysctl_set_new_value arg3 (buf_len) */ |
848 | BPF_MOV64_IMM(BPF_REG_3, 3), |
849 | |
850 | /* sysctl_set_new_value(ctx, buf, buf_len) */ |
851 | BPF_EMIT_CALL(BPF_FUNC_sysctl_set_new_value), |
852 | |
853 | /* if (ret == expected) */ |
854 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), |
855 | |
856 | /* return ALLOW; */ |
857 | BPF_MOV64_IMM(BPF_REG_0, 1), |
858 | BPF_JMP_A(1), |
859 | |
860 | /* else return DENY; */ |
861 | BPF_MOV64_IMM(BPF_REG_0, 0), |
862 | BPF_EXIT_INSN(), |
863 | }, |
864 | .attach_type = BPF_CGROUP_SYSCTL, |
865 | .sysctl = "net/ipv4/route/mtu_expires" , |
866 | .open_flags = O_WRONLY, |
867 | .newval = "606" , |
868 | .result = SUCCESS, |
869 | }, |
870 | { |
871 | "bpf_strtoul one number string" , |
872 | .insns = { |
873 | /* arg1 (buf) */ |
874 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
875 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
876 | BPF_MOV64_IMM(BPF_REG_0, |
877 | bpf_ntohl(0x36303000)), |
878 | BPF_STX_MEM(BPF_W, BPF_REG_7, BPF_REG_0, 0), |
879 | |
880 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
881 | |
882 | /* arg2 (buf_len) */ |
883 | BPF_MOV64_IMM(BPF_REG_2, 4), |
884 | |
885 | /* arg3 (flags) */ |
886 | BPF_MOV64_IMM(BPF_REG_3, 0), |
887 | |
888 | /* arg4 (res) */ |
889 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
890 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
891 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
892 | |
893 | BPF_EMIT_CALL(BPF_FUNC_strtoul), |
894 | |
895 | /* if (ret == expected && */ |
896 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 3, 4), |
897 | /* res == expected) */ |
898 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
899 | BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 600, 2), |
900 | |
901 | /* return ALLOW; */ |
902 | BPF_MOV64_IMM(BPF_REG_0, 1), |
903 | BPF_JMP_A(1), |
904 | |
905 | /* else return DENY; */ |
906 | BPF_MOV64_IMM(BPF_REG_0, 0), |
907 | BPF_EXIT_INSN(), |
908 | }, |
909 | .attach_type = BPF_CGROUP_SYSCTL, |
910 | .sysctl = "net/ipv4/route/mtu_expires" , |
911 | .open_flags = O_RDONLY, |
912 | .result = SUCCESS, |
913 | }, |
914 | { |
915 | "bpf_strtoul multi number string" , |
916 | .insns = { |
917 | /* arg1 (buf) */ |
918 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
919 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
920 | /* "600 602\0" */ |
921 | BPF_LD_IMM64(BPF_REG_0, |
922 | bpf_be64_to_cpu(0x3630302036303200ULL)), |
923 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
924 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
925 | |
926 | /* arg2 (buf_len) */ |
927 | BPF_MOV64_IMM(BPF_REG_2, 8), |
928 | |
929 | /* arg3 (flags) */ |
930 | BPF_MOV64_IMM(BPF_REG_3, 0), |
931 | |
932 | /* arg4 (res) */ |
933 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
934 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
935 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
936 | |
937 | BPF_EMIT_CALL(BPF_FUNC_strtoul), |
938 | |
939 | /* if (ret == expected && */ |
940 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 3, 18), |
941 | /* res == expected) */ |
942 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
943 | BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 600, 16), |
944 | |
945 | /* arg1 (buf) */ |
946 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
947 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
948 | BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0), |
949 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
950 | |
951 | /* arg2 (buf_len) */ |
952 | BPF_MOV64_IMM(BPF_REG_2, 8), |
953 | BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_0), |
954 | |
955 | /* arg3 (flags) */ |
956 | BPF_MOV64_IMM(BPF_REG_3, 0), |
957 | |
958 | /* arg4 (res) */ |
959 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
960 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -16), |
961 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
962 | |
963 | BPF_EMIT_CALL(BPF_FUNC_strtoul), |
964 | |
965 | /* if (ret == expected && */ |
966 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 4, 4), |
967 | /* res == expected) */ |
968 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
969 | BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 602, 2), |
970 | |
971 | /* return ALLOW; */ |
972 | BPF_MOV64_IMM(BPF_REG_0, 1), |
973 | BPF_JMP_A(1), |
974 | |
975 | /* else return DENY; */ |
976 | BPF_MOV64_IMM(BPF_REG_0, 0), |
977 | BPF_EXIT_INSN(), |
978 | }, |
979 | .attach_type = BPF_CGROUP_SYSCTL, |
980 | .sysctl = "net/ipv4/tcp_mem" , |
981 | .open_flags = O_RDONLY, |
982 | .result = SUCCESS, |
983 | }, |
984 | { |
985 | "bpf_strtoul buf_len = 0, reject" , |
986 | .insns = { |
987 | /* arg1 (buf) */ |
988 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
989 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
990 | BPF_MOV64_IMM(BPF_REG_0, |
991 | bpf_ntohl(0x36303000)), |
992 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
993 | |
994 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
995 | |
996 | /* arg2 (buf_len) */ |
997 | BPF_MOV64_IMM(BPF_REG_2, 0), |
998 | |
999 | /* arg3 (flags) */ |
1000 | BPF_MOV64_IMM(BPF_REG_3, 0), |
1001 | |
1002 | /* arg4 (res) */ |
1003 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1004 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1005 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
1006 | |
1007 | BPF_EMIT_CALL(BPF_FUNC_strtoul), |
1008 | |
1009 | BPF_MOV64_IMM(BPF_REG_0, 1), |
1010 | BPF_EXIT_INSN(), |
1011 | }, |
1012 | .attach_type = BPF_CGROUP_SYSCTL, |
1013 | .sysctl = "net/ipv4/route/mtu_expires" , |
1014 | .open_flags = O_RDONLY, |
1015 | .result = LOAD_REJECT, |
1016 | }, |
1017 | { |
1018 | "bpf_strtoul supported base, ok" , |
1019 | .insns = { |
1020 | /* arg1 (buf) */ |
1021 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
1022 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1023 | BPF_MOV64_IMM(BPF_REG_0, |
1024 | bpf_ntohl(0x30373700)), |
1025 | BPF_STX_MEM(BPF_W, BPF_REG_7, BPF_REG_0, 0), |
1026 | |
1027 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
1028 | |
1029 | /* arg2 (buf_len) */ |
1030 | BPF_MOV64_IMM(BPF_REG_2, 4), |
1031 | |
1032 | /* arg3 (flags) */ |
1033 | BPF_MOV64_IMM(BPF_REG_3, 8), |
1034 | |
1035 | /* arg4 (res) */ |
1036 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1037 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1038 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
1039 | |
1040 | BPF_EMIT_CALL(BPF_FUNC_strtoul), |
1041 | |
1042 | /* if (ret == expected && */ |
1043 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 3, 4), |
1044 | /* res == expected) */ |
1045 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
1046 | BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 63, 2), |
1047 | |
1048 | /* return ALLOW; */ |
1049 | BPF_MOV64_IMM(BPF_REG_0, 1), |
1050 | BPF_JMP_A(1), |
1051 | |
1052 | /* else return DENY; */ |
1053 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1054 | BPF_EXIT_INSN(), |
1055 | }, |
1056 | .attach_type = BPF_CGROUP_SYSCTL, |
1057 | .sysctl = "net/ipv4/route/mtu_expires" , |
1058 | .open_flags = O_RDONLY, |
1059 | .result = SUCCESS, |
1060 | }, |
1061 | { |
1062 | "bpf_strtoul unsupported base, EINVAL" , |
1063 | .insns = { |
1064 | /* arg1 (buf) */ |
1065 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
1066 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1067 | BPF_MOV64_IMM(BPF_REG_0, |
1068 | bpf_ntohl(0x36303000)), |
1069 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1070 | |
1071 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
1072 | |
1073 | /* arg2 (buf_len) */ |
1074 | BPF_MOV64_IMM(BPF_REG_2, 4), |
1075 | |
1076 | /* arg3 (flags) */ |
1077 | BPF_MOV64_IMM(BPF_REG_3, 3), |
1078 | |
1079 | /* arg4 (res) */ |
1080 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1081 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1082 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
1083 | |
1084 | BPF_EMIT_CALL(BPF_FUNC_strtoul), |
1085 | |
1086 | /* if (ret == expected) */ |
1087 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -EINVAL, 2), |
1088 | |
1089 | /* return ALLOW; */ |
1090 | BPF_MOV64_IMM(BPF_REG_0, 1), |
1091 | BPF_JMP_A(1), |
1092 | |
1093 | /* else return DENY; */ |
1094 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1095 | BPF_EXIT_INSN(), |
1096 | }, |
1097 | .attach_type = BPF_CGROUP_SYSCTL, |
1098 | .sysctl = "net/ipv4/route/mtu_expires" , |
1099 | .open_flags = O_RDONLY, |
1100 | .result = SUCCESS, |
1101 | }, |
1102 | { |
1103 | "bpf_strtoul buf with spaces only, EINVAL" , |
1104 | .insns = { |
1105 | /* arg1 (buf) */ |
1106 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
1107 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1108 | BPF_MOV64_IMM(BPF_REG_0, |
1109 | bpf_ntohl(0x0d0c0a09)), |
1110 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1111 | |
1112 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
1113 | |
1114 | /* arg2 (buf_len) */ |
1115 | BPF_MOV64_IMM(BPF_REG_2, 4), |
1116 | |
1117 | /* arg3 (flags) */ |
1118 | BPF_MOV64_IMM(BPF_REG_3, 0), |
1119 | |
1120 | /* arg4 (res) */ |
1121 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1122 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1123 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
1124 | |
1125 | BPF_EMIT_CALL(BPF_FUNC_strtoul), |
1126 | |
1127 | /* if (ret == expected) */ |
1128 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -EINVAL, 2), |
1129 | |
1130 | /* return ALLOW; */ |
1131 | BPF_MOV64_IMM(BPF_REG_0, 1), |
1132 | BPF_JMP_A(1), |
1133 | |
1134 | /* else return DENY; */ |
1135 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1136 | BPF_EXIT_INSN(), |
1137 | }, |
1138 | .attach_type = BPF_CGROUP_SYSCTL, |
1139 | .sysctl = "net/ipv4/route/mtu_expires" , |
1140 | .open_flags = O_RDONLY, |
1141 | .result = SUCCESS, |
1142 | }, |
1143 | { |
1144 | "bpf_strtoul negative number, EINVAL" , |
1145 | .insns = { |
1146 | /* arg1 (buf) */ |
1147 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
1148 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1149 | /* " -6\0" */ |
1150 | BPF_MOV64_IMM(BPF_REG_0, |
1151 | bpf_ntohl(0x0a2d3600)), |
1152 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1153 | |
1154 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
1155 | |
1156 | /* arg2 (buf_len) */ |
1157 | BPF_MOV64_IMM(BPF_REG_2, 4), |
1158 | |
1159 | /* arg3 (flags) */ |
1160 | BPF_MOV64_IMM(BPF_REG_3, 0), |
1161 | |
1162 | /* arg4 (res) */ |
1163 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1164 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1165 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
1166 | |
1167 | BPF_EMIT_CALL(BPF_FUNC_strtoul), |
1168 | |
1169 | /* if (ret == expected) */ |
1170 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -EINVAL, 2), |
1171 | |
1172 | /* return ALLOW; */ |
1173 | BPF_MOV64_IMM(BPF_REG_0, 1), |
1174 | BPF_JMP_A(1), |
1175 | |
1176 | /* else return DENY; */ |
1177 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1178 | BPF_EXIT_INSN(), |
1179 | }, |
1180 | .attach_type = BPF_CGROUP_SYSCTL, |
1181 | .sysctl = "net/ipv4/route/mtu_expires" , |
1182 | .open_flags = O_RDONLY, |
1183 | .result = SUCCESS, |
1184 | }, |
1185 | { |
1186 | "bpf_strtol negative number, ok" , |
1187 | .insns = { |
1188 | /* arg1 (buf) */ |
1189 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
1190 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1191 | /* " -6\0" */ |
1192 | BPF_MOV64_IMM(BPF_REG_0, |
1193 | bpf_ntohl(0x0a2d3600)), |
1194 | BPF_STX_MEM(BPF_W, BPF_REG_7, BPF_REG_0, 0), |
1195 | |
1196 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
1197 | |
1198 | /* arg2 (buf_len) */ |
1199 | BPF_MOV64_IMM(BPF_REG_2, 4), |
1200 | |
1201 | /* arg3 (flags) */ |
1202 | BPF_MOV64_IMM(BPF_REG_3, 10), |
1203 | |
1204 | /* arg4 (res) */ |
1205 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1206 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1207 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
1208 | |
1209 | BPF_EMIT_CALL(BPF_FUNC_strtol), |
1210 | |
1211 | /* if (ret == expected && */ |
1212 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 3, 4), |
1213 | /* res == expected) */ |
1214 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
1215 | BPF_JMP_IMM(BPF_JNE, BPF_REG_9, -6, 2), |
1216 | |
1217 | /* return ALLOW; */ |
1218 | BPF_MOV64_IMM(BPF_REG_0, 1), |
1219 | BPF_JMP_A(1), |
1220 | |
1221 | /* else return DENY; */ |
1222 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1223 | BPF_EXIT_INSN(), |
1224 | }, |
1225 | .attach_type = BPF_CGROUP_SYSCTL, |
1226 | .sysctl = "net/ipv4/route/mtu_expires" , |
1227 | .open_flags = O_RDONLY, |
1228 | .result = SUCCESS, |
1229 | }, |
1230 | { |
1231 | "bpf_strtol hex number, ok" , |
1232 | .insns = { |
1233 | /* arg1 (buf) */ |
1234 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
1235 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1236 | /* "0xfe" */ |
1237 | BPF_MOV64_IMM(BPF_REG_0, |
1238 | bpf_ntohl(0x30786665)), |
1239 | BPF_STX_MEM(BPF_W, BPF_REG_7, BPF_REG_0, 0), |
1240 | |
1241 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
1242 | |
1243 | /* arg2 (buf_len) */ |
1244 | BPF_MOV64_IMM(BPF_REG_2, 4), |
1245 | |
1246 | /* arg3 (flags) */ |
1247 | BPF_MOV64_IMM(BPF_REG_3, 0), |
1248 | |
1249 | /* arg4 (res) */ |
1250 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1251 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1252 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
1253 | |
1254 | BPF_EMIT_CALL(BPF_FUNC_strtol), |
1255 | |
1256 | /* if (ret == expected && */ |
1257 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 4, 4), |
1258 | /* res == expected) */ |
1259 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
1260 | BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 254, 2), |
1261 | |
1262 | /* return ALLOW; */ |
1263 | BPF_MOV64_IMM(BPF_REG_0, 1), |
1264 | BPF_JMP_A(1), |
1265 | |
1266 | /* else return DENY; */ |
1267 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1268 | BPF_EXIT_INSN(), |
1269 | }, |
1270 | .attach_type = BPF_CGROUP_SYSCTL, |
1271 | .sysctl = "net/ipv4/route/mtu_expires" , |
1272 | .open_flags = O_RDONLY, |
1273 | .result = SUCCESS, |
1274 | }, |
1275 | { |
1276 | "bpf_strtol max long" , |
1277 | .insns = { |
1278 | /* arg1 (buf) 9223372036854775807 */ |
1279 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
1280 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -24), |
1281 | BPF_LD_IMM64(BPF_REG_0, |
1282 | bpf_be64_to_cpu(0x3932323333373230ULL)), |
1283 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1284 | BPF_LD_IMM64(BPF_REG_0, |
1285 | bpf_be64_to_cpu(0x3336383534373735ULL)), |
1286 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 8), |
1287 | BPF_LD_IMM64(BPF_REG_0, |
1288 | bpf_be64_to_cpu(0x3830370000000000ULL)), |
1289 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 16), |
1290 | |
1291 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
1292 | |
1293 | /* arg2 (buf_len) */ |
1294 | BPF_MOV64_IMM(BPF_REG_2, 19), |
1295 | |
1296 | /* arg3 (flags) */ |
1297 | BPF_MOV64_IMM(BPF_REG_3, 0), |
1298 | |
1299 | /* arg4 (res) */ |
1300 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1301 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1302 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
1303 | |
1304 | BPF_EMIT_CALL(BPF_FUNC_strtol), |
1305 | |
1306 | /* if (ret == expected && */ |
1307 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 19, 6), |
1308 | /* res == expected) */ |
1309 | BPF_LD_IMM64(BPF_REG_8, 0x7fffffffffffffffULL), |
1310 | BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0), |
1311 | BPF_JMP_REG(BPF_JNE, BPF_REG_8, BPF_REG_9, 2), |
1312 | |
1313 | /* return ALLOW; */ |
1314 | BPF_MOV64_IMM(BPF_REG_0, 1), |
1315 | BPF_JMP_A(1), |
1316 | |
1317 | /* else return DENY; */ |
1318 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1319 | BPF_EXIT_INSN(), |
1320 | }, |
1321 | .attach_type = BPF_CGROUP_SYSCTL, |
1322 | .sysctl = "net/ipv4/route/mtu_expires" , |
1323 | .open_flags = O_RDONLY, |
1324 | .result = SUCCESS, |
1325 | }, |
1326 | { |
1327 | "bpf_strtol overflow, ERANGE" , |
1328 | .insns = { |
1329 | /* arg1 (buf) 9223372036854775808 */ |
1330 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_10), |
1331 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -24), |
1332 | BPF_LD_IMM64(BPF_REG_0, |
1333 | bpf_be64_to_cpu(0x3932323333373230ULL)), |
1334 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1335 | BPF_LD_IMM64(BPF_REG_0, |
1336 | bpf_be64_to_cpu(0x3336383534373735ULL)), |
1337 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 8), |
1338 | BPF_LD_IMM64(BPF_REG_0, |
1339 | bpf_be64_to_cpu(0x3830380000000000ULL)), |
1340 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 16), |
1341 | |
1342 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), |
1343 | |
1344 | /* arg2 (buf_len) */ |
1345 | BPF_MOV64_IMM(BPF_REG_2, 19), |
1346 | |
1347 | /* arg3 (flags) */ |
1348 | BPF_MOV64_IMM(BPF_REG_3, 0), |
1349 | |
1350 | /* arg4 (res) */ |
1351 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -8), |
1352 | BPF_STX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0), |
1353 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_7), |
1354 | |
1355 | BPF_EMIT_CALL(BPF_FUNC_strtol), |
1356 | |
1357 | /* if (ret == expected) */ |
1358 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, -ERANGE, 2), |
1359 | |
1360 | /* return ALLOW; */ |
1361 | BPF_MOV64_IMM(BPF_REG_0, 1), |
1362 | BPF_JMP_A(1), |
1363 | |
1364 | /* else return DENY; */ |
1365 | BPF_MOV64_IMM(BPF_REG_0, 0), |
1366 | BPF_EXIT_INSN(), |
1367 | }, |
1368 | .attach_type = BPF_CGROUP_SYSCTL, |
1369 | .sysctl = "net/ipv4/route/mtu_expires" , |
1370 | .open_flags = O_RDONLY, |
1371 | .result = SUCCESS, |
1372 | }, |
1373 | { |
1374 | "C prog: deny all writes" , |
1375 | .prog_file = "./test_sysctl_prog.bpf.o" , |
1376 | .attach_type = BPF_CGROUP_SYSCTL, |
1377 | .sysctl = "net/ipv4/tcp_mem" , |
1378 | .open_flags = O_WRONLY, |
1379 | .newval = "123 456 789" , |
1380 | .result = OP_EPERM, |
1381 | }, |
1382 | { |
1383 | "C prog: deny access by name" , |
1384 | .prog_file = "./test_sysctl_prog.bpf.o" , |
1385 | .attach_type = BPF_CGROUP_SYSCTL, |
1386 | .sysctl = "net/ipv4/route/mtu_expires" , |
1387 | .open_flags = O_RDONLY, |
1388 | .result = OP_EPERM, |
1389 | }, |
1390 | { |
1391 | "C prog: read tcp_mem" , |
1392 | .prog_file = "./test_sysctl_prog.bpf.o" , |
1393 | .attach_type = BPF_CGROUP_SYSCTL, |
1394 | .sysctl = "net/ipv4/tcp_mem" , |
1395 | .open_flags = O_RDONLY, |
1396 | .result = SUCCESS, |
1397 | }, |
1398 | }; |
1399 | |
1400 | static size_t probe_prog_length(const struct bpf_insn *fp) |
1401 | { |
1402 | size_t len; |
1403 | |
1404 | for (len = MAX_INSNS - 1; len > 0; --len) |
1405 | if (fp[len].code != 0 || fp[len].imm != 0) |
1406 | break; |
1407 | return len + 1; |
1408 | } |
1409 | |
1410 | static int fixup_sysctl_value(const char *buf, size_t buf_len, |
1411 | struct bpf_insn *prog, size_t insn_num) |
1412 | { |
1413 | union { |
1414 | uint8_t raw[sizeof(uint64_t)]; |
1415 | uint64_t num; |
1416 | } value = {}; |
1417 | |
1418 | if (buf_len > sizeof(value)) { |
1419 | log_err("Value is too big (%zd) to use in fixup" , buf_len); |
1420 | return -1; |
1421 | } |
1422 | if (prog[insn_num].code != (BPF_LD | BPF_DW | BPF_IMM)) { |
1423 | log_err("Can fixup only BPF_LD_IMM64 insns" ); |
1424 | return -1; |
1425 | } |
1426 | |
1427 | memcpy(value.raw, buf, buf_len); |
1428 | prog[insn_num].imm = (uint32_t)value.num; |
1429 | prog[insn_num + 1].imm = (uint32_t)(value.num >> 32); |
1430 | |
1431 | return 0; |
1432 | } |
1433 | |
1434 | static int load_sysctl_prog_insns(struct sysctl_test *test, |
1435 | const char *sysctl_path) |
1436 | { |
1437 | struct bpf_insn *prog = test->insns; |
1438 | LIBBPF_OPTS(bpf_prog_load_opts, opts); |
1439 | int ret, insn_cnt; |
1440 | |
1441 | insn_cnt = probe_prog_length(fp: prog); |
1442 | |
1443 | if (test->fixup_value_insn) { |
1444 | char buf[128]; |
1445 | ssize_t len; |
1446 | int fd; |
1447 | |
1448 | fd = open(sysctl_path, O_RDONLY | O_CLOEXEC); |
1449 | if (fd < 0) { |
1450 | log_err("open(%s) failed" , sysctl_path); |
1451 | return -1; |
1452 | } |
1453 | len = read(fd, buf, sizeof(buf)); |
1454 | if (len == -1) { |
1455 | log_err("read(%s) failed" , sysctl_path); |
1456 | close(fd); |
1457 | return -1; |
1458 | } |
1459 | close(fd); |
1460 | if (fixup_sysctl_value(buf, buf_len: len, prog, insn_num: test->fixup_value_insn)) |
1461 | return -1; |
1462 | } |
1463 | |
1464 | opts.log_buf = bpf_log_buf; |
1465 | opts.log_size = BPF_LOG_BUF_SIZE; |
1466 | |
1467 | ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SYSCTL, NULL, "GPL" , prog, insn_cnt, &opts); |
1468 | if (ret < 0 && test->result != LOAD_REJECT) { |
1469 | log_err(">>> Loading program error.\n" |
1470 | ">>> Verifier output:\n%s\n-------\n" , bpf_log_buf); |
1471 | } |
1472 | |
1473 | return ret; |
1474 | } |
1475 | |
1476 | static int load_sysctl_prog_file(struct sysctl_test *test) |
1477 | { |
1478 | struct bpf_object *obj; |
1479 | int prog_fd; |
1480 | |
1481 | if (bpf_prog_test_load(file: test->prog_file, type: BPF_PROG_TYPE_CGROUP_SYSCTL, pobj: &obj, prog_fd: &prog_fd)) { |
1482 | if (test->result != LOAD_REJECT) |
1483 | log_err(">>> Loading program (%s) error.\n" , |
1484 | test->prog_file); |
1485 | return -1; |
1486 | } |
1487 | |
1488 | return prog_fd; |
1489 | } |
1490 | |
1491 | static int load_sysctl_prog(struct sysctl_test *test, const char *sysctl_path) |
1492 | { |
1493 | return test->prog_file |
1494 | ? load_sysctl_prog_file(test) |
1495 | : load_sysctl_prog_insns(test, sysctl_path); |
1496 | } |
1497 | |
1498 | static int access_sysctl(const char *sysctl_path, |
1499 | const struct sysctl_test *test) |
1500 | { |
1501 | int err = 0; |
1502 | int fd; |
1503 | |
1504 | fd = open(sysctl_path, test->open_flags | O_CLOEXEC); |
1505 | if (fd < 0) |
1506 | return fd; |
1507 | |
1508 | if (test->seek && lseek(fd, test->seek, SEEK_SET) == -1) { |
1509 | log_err("lseek(%d) failed" , test->seek); |
1510 | goto err; |
1511 | } |
1512 | |
1513 | if (test->open_flags == O_RDONLY) { |
1514 | char buf[128]; |
1515 | |
1516 | if (read(fd, buf, sizeof(buf)) == -1) |
1517 | goto err; |
1518 | if (test->oldval && |
1519 | strncmp(buf, test->oldval, strlen(test->oldval))) { |
1520 | log_err("Read value %s != %s" , buf, test->oldval); |
1521 | goto err; |
1522 | } |
1523 | } else if (test->open_flags == O_WRONLY) { |
1524 | if (!test->newval) { |
1525 | log_err("New value for sysctl is not set" ); |
1526 | goto err; |
1527 | } |
1528 | if (write(fd, test->newval, strlen(test->newval)) == -1) |
1529 | goto err; |
1530 | } else { |
1531 | log_err("Unexpected sysctl access: neither read nor write" ); |
1532 | goto err; |
1533 | } |
1534 | |
1535 | goto out; |
1536 | err: |
1537 | err = -1; |
1538 | out: |
1539 | close(fd); |
1540 | return err; |
1541 | } |
1542 | |
1543 | static int run_test_case(int cgfd, struct sysctl_test *test) |
1544 | { |
1545 | enum bpf_attach_type atype = test->attach_type; |
1546 | char sysctl_path[128]; |
1547 | int progfd = -1; |
1548 | int err = 0; |
1549 | |
1550 | printf("Test case: %s .. " , test->descr); |
1551 | |
1552 | snprintf(buf: sysctl_path, size: sizeof(sysctl_path), fmt: "/proc/sys/%s" , |
1553 | test->sysctl); |
1554 | |
1555 | progfd = load_sysctl_prog(test, sysctl_path); |
1556 | if (progfd < 0) { |
1557 | if (test->result == LOAD_REJECT) |
1558 | goto out; |
1559 | else |
1560 | goto err; |
1561 | } |
1562 | |
1563 | if (bpf_prog_attach(progfd, cgfd, atype, BPF_F_ALLOW_OVERRIDE) < 0) { |
1564 | if (test->result == ATTACH_REJECT) |
1565 | goto out; |
1566 | else |
1567 | goto err; |
1568 | } |
1569 | |
1570 | errno = 0; |
1571 | if (access_sysctl(sysctl_path, test) == -1) { |
1572 | if (test->result == OP_EPERM && errno == EPERM) |
1573 | goto out; |
1574 | else |
1575 | goto err; |
1576 | } |
1577 | |
1578 | if (test->result != SUCCESS) { |
1579 | log_err("Unexpected success" ); |
1580 | goto err; |
1581 | } |
1582 | |
1583 | goto out; |
1584 | err: |
1585 | err = -1; |
1586 | out: |
1587 | /* Detaching w/o checking return code: best effort attempt. */ |
1588 | if (progfd != -1) |
1589 | bpf_prog_detach(cgfd, atype); |
1590 | close(progfd); |
1591 | printf("[%s]\n" , err ? "FAIL" : "PASS" ); |
1592 | return err; |
1593 | } |
1594 | |
1595 | static int run_tests(int cgfd) |
1596 | { |
1597 | int passes = 0; |
1598 | int fails = 0; |
1599 | int i; |
1600 | |
1601 | for (i = 0; i < ARRAY_SIZE(tests); ++i) { |
1602 | if (run_test_case(cgfd, &tests[i])) |
1603 | ++fails; |
1604 | else |
1605 | ++passes; |
1606 | } |
1607 | printf("Summary: %d PASSED, %d FAILED\n" , passes, fails); |
1608 | return fails ? -1 : 0; |
1609 | } |
1610 | |
1611 | int main(int argc, char **argv) |
1612 | { |
1613 | int cgfd = -1; |
1614 | int err = 0; |
1615 | |
1616 | cgfd = cgroup_setup_and_join(CG_PATH); |
1617 | if (cgfd < 0) |
1618 | goto err; |
1619 | |
1620 | /* Use libbpf 1.0 API mode */ |
1621 | libbpf_set_strict_mode(LIBBPF_STRICT_ALL); |
1622 | |
1623 | if (run_tests(cgfd)) |
1624 | goto err; |
1625 | |
1626 | goto out; |
1627 | err: |
1628 | err = -1; |
1629 | out: |
1630 | close(cgfd); |
1631 | cleanup_cgroup_environment(); |
1632 | return err; |
1633 | } |
1634 | |