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