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