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