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