xref: /linux/tools/testing/selftests/bpf/test_sysctl.c (revision 64b14a184e83eb62ea0615e31a409956049d40e7)
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 
26 char bpf_log_buf[BPF_LOG_BUF_SIZE];
27 
28 struct 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 
47 static 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 
1401 static 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 
1411 static 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 
1435 static 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 
1477 static 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 
1492 static 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 
1499 static 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;
1537 err:
1538 	err = -1;
1539 out:
1540 	close(fd);
1541 	return err;
1542 }
1543 
1544 static 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;
1585 err:
1586 	err = -1;
1587 out:
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 
1596 static 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 
1612 int 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;
1625 err:
1626 	err = -1;
1627 out:
1628 	close(cgfd);
1629 	cleanup_cgroup_environment();
1630 	return err;
1631 }
1632