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