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