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