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