Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

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