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