cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

test_sysctl.c (41072B)


      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/bpf_endian.h>
     17#include "bpf_util.h"
     18#include "cgroup_helpers.h"
     19#include "testing_helpers.h"
     20
     21#define CG_PATH			"/foo"
     22#define MAX_INSNS		512
     23#define FIXUP_SYSCTL_VALUE	0
     24
     25char bpf_log_buf[BPF_LOG_BUF_SIZE];
     26
     27struct 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
     46static 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__ == __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__ == __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
   1400static 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
   1410static 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
   1434static int load_sysctl_prog_insns(struct sysctl_test *test,
   1435				  const char *sysctl_path)
   1436{
   1437	struct bpf_insn *prog = test->insns;
   1438	LIBBPF_OPTS(bpf_prog_load_opts, opts);
   1439	int ret, insn_cnt;
   1440
   1441	insn_cnt = probe_prog_length(prog);
   1442
   1443	if (test->fixup_value_insn) {
   1444		char buf[128];
   1445		ssize_t len;
   1446		int fd;
   1447
   1448		fd = open(sysctl_path, O_RDONLY | O_CLOEXEC);
   1449		if (fd < 0) {
   1450			log_err("open(%s) failed", sysctl_path);
   1451			return -1;
   1452		}
   1453		len = read(fd, buf, sizeof(buf));
   1454		if (len == -1) {
   1455			log_err("read(%s) failed", sysctl_path);
   1456			close(fd);
   1457			return -1;
   1458		}
   1459		close(fd);
   1460		if (fixup_sysctl_value(buf, len, prog, test->fixup_value_insn))
   1461			return -1;
   1462	}
   1463
   1464	opts.log_buf = bpf_log_buf;
   1465	opts.log_size = BPF_LOG_BUF_SIZE;
   1466
   1467	ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SYSCTL, NULL, "GPL", prog, insn_cnt, &opts);
   1468	if (ret < 0 && test->result != LOAD_REJECT) {
   1469		log_err(">>> Loading program error.\n"
   1470			">>> Verifier output:\n%s\n-------\n", bpf_log_buf);
   1471	}
   1472
   1473	return ret;
   1474}
   1475
   1476static int load_sysctl_prog_file(struct sysctl_test *test)
   1477{
   1478	struct bpf_object *obj;
   1479	int prog_fd;
   1480
   1481	if (bpf_prog_test_load(test->prog_file, BPF_PROG_TYPE_CGROUP_SYSCTL, &obj, &prog_fd)) {
   1482		if (test->result != LOAD_REJECT)
   1483			log_err(">>> Loading program (%s) error.\n",
   1484				test->prog_file);
   1485		return -1;
   1486	}
   1487
   1488	return prog_fd;
   1489}
   1490
   1491static int load_sysctl_prog(struct sysctl_test *test, const char *sysctl_path)
   1492{
   1493		return test->prog_file
   1494			? load_sysctl_prog_file(test)
   1495			: load_sysctl_prog_insns(test, sysctl_path);
   1496}
   1497
   1498static int access_sysctl(const char *sysctl_path,
   1499			 const struct sysctl_test *test)
   1500{
   1501	int err = 0;
   1502	int fd;
   1503
   1504	fd = open(sysctl_path, test->open_flags | O_CLOEXEC);
   1505	if (fd < 0)
   1506		return fd;
   1507
   1508	if (test->seek && lseek(fd, test->seek, SEEK_SET) == -1) {
   1509		log_err("lseek(%d) failed", test->seek);
   1510		goto err;
   1511	}
   1512
   1513	if (test->open_flags == O_RDONLY) {
   1514		char buf[128];
   1515
   1516		if (read(fd, buf, sizeof(buf)) == -1)
   1517			goto err;
   1518		if (test->oldval &&
   1519		    strncmp(buf, test->oldval, strlen(test->oldval))) {
   1520			log_err("Read value %s != %s", buf, test->oldval);
   1521			goto err;
   1522		}
   1523	} else if (test->open_flags == O_WRONLY) {
   1524		if (!test->newval) {
   1525			log_err("New value for sysctl is not set");
   1526			goto err;
   1527		}
   1528		if (write(fd, test->newval, strlen(test->newval)) == -1)
   1529			goto err;
   1530	} else {
   1531		log_err("Unexpected sysctl access: neither read nor write");
   1532		goto err;
   1533	}
   1534
   1535	goto out;
   1536err:
   1537	err = -1;
   1538out:
   1539	close(fd);
   1540	return err;
   1541}
   1542
   1543static int run_test_case(int cgfd, struct sysctl_test *test)
   1544{
   1545	enum bpf_attach_type atype = test->attach_type;
   1546	char sysctl_path[128];
   1547	int progfd = -1;
   1548	int err = 0;
   1549
   1550	printf("Test case: %s .. ", test->descr);
   1551
   1552	snprintf(sysctl_path, sizeof(sysctl_path), "/proc/sys/%s",
   1553		 test->sysctl);
   1554
   1555	progfd = load_sysctl_prog(test, sysctl_path);
   1556	if (progfd < 0) {
   1557		if (test->result == LOAD_REJECT)
   1558			goto out;
   1559		else
   1560			goto err;
   1561	}
   1562
   1563	if (bpf_prog_attach(progfd, cgfd, atype, BPF_F_ALLOW_OVERRIDE) < 0) {
   1564		if (test->result == ATTACH_REJECT)
   1565			goto out;
   1566		else
   1567			goto err;
   1568	}
   1569
   1570	errno = 0;
   1571	if (access_sysctl(sysctl_path, test) == -1) {
   1572		if (test->result == OP_EPERM && errno == EPERM)
   1573			goto out;
   1574		else
   1575			goto err;
   1576	}
   1577
   1578	if (test->result != SUCCESS) {
   1579		log_err("Unexpected success");
   1580		goto err;
   1581	}
   1582
   1583	goto out;
   1584err:
   1585	err = -1;
   1586out:
   1587	/* Detaching w/o checking return code: best effort attempt. */
   1588	if (progfd != -1)
   1589		bpf_prog_detach(cgfd, atype);
   1590	close(progfd);
   1591	printf("[%s]\n", err ? "FAIL" : "PASS");
   1592	return err;
   1593}
   1594
   1595static int run_tests(int cgfd)
   1596{
   1597	int passes = 0;
   1598	int fails = 0;
   1599	int i;
   1600
   1601	for (i = 0; i < ARRAY_SIZE(tests); ++i) {
   1602		if (run_test_case(cgfd, &tests[i]))
   1603			++fails;
   1604		else
   1605			++passes;
   1606	}
   1607	printf("Summary: %d PASSED, %d FAILED\n", passes, fails);
   1608	return fails ? -1 : 0;
   1609}
   1610
   1611int main(int argc, char **argv)
   1612{
   1613	int cgfd = -1;
   1614	int err = 0;
   1615
   1616	cgfd = cgroup_setup_and_join(CG_PATH);
   1617	if (cgfd < 0)
   1618		goto err;
   1619
   1620	/* Use libbpf 1.0 API mode */
   1621	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
   1622
   1623	if (run_tests(cgfd))
   1624		goto err;
   1625
   1626	goto out;
   1627err:
   1628	err = -1;
   1629out:
   1630	close(cgfd);
   1631	cleanup_cgroup_environment();
   1632	return err;
   1633}