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