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