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