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