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