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