Linux Audio

Check our new training course

Buildroot integration, development and maintenance

Need a Buildroot system for your embedded project?
Loading...
Note: File does not exist in v4.10.11.
   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}