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