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