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