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
probe_prog_length(const struct bpf_insn * fp)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
fixup_sysctl_value(const char * buf,size_t buf_len,struct bpf_insn * prog,size_t insn_num)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
load_sysctl_prog_insns(struct sysctl_test * test,const char * sysctl_path)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(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, len, prog, 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
load_sysctl_prog_file(struct sysctl_test * test)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(test->prog_file, BPF_PROG_TYPE_CGROUP_SYSCTL, &obj, &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
load_sysctl_prog(struct sysctl_test * test,const char * sysctl_path)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
access_sysctl(const char * sysctl_path,const struct sysctl_test * test)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
run_test_case(int cgfd,struct sysctl_test * test)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(sysctl_path, sizeof(sysctl_path), "/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
run_tests(int cgfd)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
main(int argc,char ** argv)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