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