linux/tools/testing/selftests/bpf/test_sysctl.c
<<
>>
Prefs
   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}
1620