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