Linux Audio

Check our new training course

Loading...
v6.13.7
   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.bpf.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.bpf.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.bpf.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}
v6.8
   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.bpf.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.bpf.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.bpf.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}