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