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