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