1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3 4 #include <vmlinux.h> 5 #include <bpf/bpf_helpers.h> 6 #include <bpf/bpf_tracing.h> 7 #include "bpf_misc.h" 8 #include "xdp_metadata.h" 9 #include "bpf_kfuncs.h" 10 #include "err.h" 11 12 /* The compiler may be able to detect the access to uninitialized 13 memory in the routines performing out of bound memory accesses and 14 emit warnings about it. This is the case of GCC. */ 15 #if !defined(__clang__) 16 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 17 #endif 18 19 int arr[1]; 20 int unkn_idx; 21 const volatile bool call_dead_subprog = false; 22 23 __noinline long global_bad(void) 24 { 25 return arr[unkn_idx]; /* BOOM */ 26 } 27 28 __noinline long global_good(void) 29 { 30 return arr[0]; 31 } 32 33 __noinline long global_calls_bad(void) 34 { 35 return global_good() + global_bad() /* does BOOM indirectly */; 36 } 37 38 __noinline long global_calls_good_only(void) 39 { 40 return global_good(); 41 } 42 43 __noinline long global_dead(void) 44 { 45 return arr[0] * 2; 46 } 47 48 SEC("?raw_tp") 49 __success __log_level(6) 50 /* main prog is validated completely first */ 51 __msg("('global_calls_good_only') is global and assumed valid.") 52 /* eventually global_good() is transitively validated as well */ 53 __msg("Validating global_good() func") 54 __msg("('global_good') is safe for any args that match its prototype") 55 __msg("insns processed {{[0-9]+\\+[0-9]+\\+[0-9]+$}}") 56 int chained_global_func_calls_success(void) 57 { 58 int sum = 0; 59 60 if (call_dead_subprog) 61 sum += global_dead(); 62 return global_calls_good_only() + sum; 63 } 64 65 SEC("?raw_tp") 66 __failure __log_level(2) 67 /* main prog validated successfully first */ 68 __msg("('global_calls_bad') is global and assumed valid.") 69 /* eventually we validate global_bad() and fail */ 70 __msg("Validating global_bad() func") 71 __msg("math between map_value pointer and register") /* BOOM */ 72 int chained_global_func_calls_bad(void) 73 { 74 return global_calls_bad(); 75 } 76 77 /* do out of bounds access forcing verifier to fail verification if this 78 * global func is called 79 */ 80 __noinline int global_unsupp(const int *mem) 81 { 82 if (!mem) 83 return 0; 84 return mem[100]; /* BOOM */ 85 } 86 87 const volatile bool skip_unsupp_global = true; 88 89 SEC("?raw_tp") 90 __success 91 int guarded_unsupp_global_called(void) 92 { 93 if (!skip_unsupp_global) 94 return global_unsupp(NULL); 95 return 0; 96 } 97 98 SEC("?raw_tp") 99 __failure __log_level(2) 100 __msg("Func#1 ('global_unsupp') is global and assumed valid.") 101 __msg("Validating global_unsupp() func#1...") 102 __msg("value is outside of the allowed memory range") 103 int unguarded_unsupp_global_called(void) 104 { 105 int x = 0; 106 107 return global_unsupp(&x); 108 } 109 110 long stack[128]; 111 112 __weak int subprog_nullable_ptr_bad(int *p) 113 { 114 return (*p) * 2; /* bad, missing null check */ 115 } 116 117 SEC("?raw_tp") 118 __failure __log_level(2) 119 __msg("invalid mem access 'mem_or_null'") 120 int arg_tag_nullable_ptr_fail(void *ctx) 121 { 122 int x = 42; 123 124 return subprog_nullable_ptr_bad(&x); 125 } 126 127 typedef struct { 128 int x; 129 } user_struct_t; 130 131 __noinline __weak int subprog_user_anon_mem(user_struct_t *t) 132 { 133 return t ? t->x : 0; 134 } 135 136 SEC("?tracepoint") 137 __failure __log_level(2) 138 __msg("Caller passes invalid args into func#1 ('subprog_user_anon_mem')") 139 int anon_user_mem_invalid(void *ctx) 140 { 141 /* can't pass PTR_TO_CTX as user memory */ 142 return subprog_user_anon_mem(ctx); 143 } 144 145 SEC("?tracepoint") 146 __success __log_level(2) 147 __msg("Func#1 ('subprog_user_anon_mem') is safe for any args that match its prototype") 148 int anon_user_mem_valid(void *ctx) 149 { 150 user_struct_t t = { .x = 42 }; 151 152 return subprog_user_anon_mem(&t); 153 } 154 155 __noinline __weak int subprog_user_anon_mem_huge(int (*p)[0x3fffffff]) 156 { 157 return p ? (*p)[1] : 0; 158 } 159 160 SEC("?tracepoint") 161 __failure __log_level(2) 162 __msg("R1 memory size 4294967292 is too large") 163 int anon_user_mem_huge_size_invalid(void *ctx) 164 { 165 int (*p)[0x3fffffff]; 166 int tiny = 42; 167 168 p = (void *)&tiny; 169 return subprog_user_anon_mem_huge(p) + tiny; 170 } 171 172 __noinline __weak int subprog_nonnull_ptr_good(int *p1 __arg_nonnull, int *p2 __arg_nonnull) 173 { 174 return (*p1) * (*p2); /* good, no need for NULL checks */ 175 } 176 177 int x = 47; 178 179 SEC("?raw_tp") 180 __success __log_level(2) 181 int arg_tag_nonnull_ptr_good(void *ctx) 182 { 183 int y = 74; 184 185 return subprog_nonnull_ptr_good(&x, &y); 186 } 187 188 /* this global subprog can be now called from many types of entry progs, each 189 * with different context type 190 */ 191 __weak int subprog_ctx_tag(void *ctx __arg_ctx) 192 { 193 return bpf_get_stack(ctx, stack, sizeof(stack), 0); 194 } 195 196 __weak int raw_tp_canonical(struct bpf_raw_tracepoint_args *ctx __arg_ctx) 197 { 198 return 0; 199 } 200 201 __weak int raw_tp_u64_array(u64 *ctx __arg_ctx) 202 { 203 return 0; 204 } 205 206 SEC("?raw_tp") 207 __success __log_level(2) 208 int arg_tag_ctx_raw_tp(void *ctx) 209 { 210 return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx); 211 } 212 213 SEC("?raw_tp.w") 214 __success __log_level(2) 215 int arg_tag_ctx_raw_tp_writable(void *ctx) 216 { 217 return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx); 218 } 219 220 SEC("?tp_btf/sys_enter") 221 __success __log_level(2) 222 int arg_tag_ctx_raw_tp_btf(void *ctx) 223 { 224 return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx); 225 } 226 227 struct whatever { }; 228 229 __weak int tp_whatever(struct whatever *ctx __arg_ctx) 230 { 231 return 0; 232 } 233 234 SEC("?tp") 235 __success __log_level(2) 236 int arg_tag_ctx_tp(void *ctx) 237 { 238 return subprog_ctx_tag(ctx) + tp_whatever(ctx); 239 } 240 241 __weak int kprobe_subprog_pt_regs(struct pt_regs *ctx __arg_ctx) 242 { 243 return 0; 244 } 245 246 __weak int kprobe_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx) 247 { 248 return 0; 249 } 250 251 SEC("?kprobe") 252 __success __log_level(2) 253 int arg_tag_ctx_kprobe(void *ctx) 254 { 255 return subprog_ctx_tag(ctx) + 256 kprobe_subprog_pt_regs(ctx) + 257 kprobe_subprog_typedef(ctx); 258 } 259 260 __weak int perf_subprog_regs( 261 #if defined(bpf_target_riscv) 262 struct user_regs_struct *ctx __arg_ctx 263 #elif defined(bpf_target_s390) 264 /* user_pt_regs typedef is anonymous struct, so only `void *` works */ 265 void *ctx __arg_ctx 266 #elif defined(bpf_target_loongarch) || defined(bpf_target_arm64) || defined(bpf_target_powerpc) 267 struct user_pt_regs *ctx __arg_ctx 268 #else 269 struct pt_regs *ctx __arg_ctx 270 #endif 271 ) 272 { 273 return 0; 274 } 275 276 __weak int perf_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx) 277 { 278 return 0; 279 } 280 281 __weak int perf_subprog_canonical(struct bpf_perf_event_data *ctx __arg_ctx) 282 { 283 return 0; 284 } 285 286 SEC("?perf_event") 287 __success __log_level(2) 288 int arg_tag_ctx_perf(void *ctx) 289 { 290 return subprog_ctx_tag(ctx) + 291 perf_subprog_regs(ctx) + 292 perf_subprog_typedef(ctx) + 293 perf_subprog_canonical(ctx); 294 } 295 296 __weak int iter_subprog_void(void *ctx __arg_ctx) 297 { 298 return 0; 299 } 300 301 __weak int iter_subprog_typed(struct bpf_iter__task *ctx __arg_ctx) 302 { 303 return 0; 304 } 305 306 SEC("?iter/task") 307 __success __log_level(2) 308 int arg_tag_ctx_iter_task(struct bpf_iter__task *ctx) 309 { 310 return (iter_subprog_void(ctx) + iter_subprog_typed(ctx)) & 1; 311 } 312 313 __weak int tracing_subprog_void(void *ctx __arg_ctx) 314 { 315 return 0; 316 } 317 318 __weak int tracing_subprog_u64(u64 *ctx __arg_ctx) 319 { 320 return 0; 321 } 322 323 int acc; 324 325 SEC("?fentry/" SYS_PREFIX "sys_nanosleep") 326 __success __log_level(2) 327 int BPF_PROG(arg_tag_ctx_fentry) 328 { 329 acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); 330 return 0; 331 } 332 333 SEC("?fexit/" SYS_PREFIX "sys_nanosleep") 334 __success __log_level(2) 335 int BPF_PROG(arg_tag_ctx_fexit) 336 { 337 acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); 338 return 0; 339 } 340 341 SEC("?fmod_ret/" SYS_PREFIX "sys_nanosleep") 342 __success __log_level(2) 343 int BPF_PROG(arg_tag_ctx_fmod_ret) 344 { 345 return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); 346 } 347 348 SEC("?lsm/bpf") 349 __success __log_level(2) 350 int BPF_PROG(arg_tag_ctx_lsm) 351 { 352 int ret; 353 354 ret = tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); 355 set_if_not_errno_or_zero(ret, -1); 356 return ret; 357 } 358 359 SEC("?struct_ops/test_1") 360 __success __log_level(2) 361 int BPF_PROG(arg_tag_ctx_struct_ops) 362 { 363 return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); 364 } 365 366 SEC(".struct_ops") 367 struct bpf_dummy_ops dummy_1 = { 368 .test_1 = (void *)arg_tag_ctx_struct_ops, 369 }; 370 371 SEC("?syscall") 372 __success __log_level(2) 373 int arg_tag_ctx_syscall(void *ctx) 374 { 375 return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx) + tp_whatever(ctx); 376 } 377 378 __weak int syscall_array_bpf_for(void *ctx __arg_ctx) 379 { 380 int *arr = ctx; 381 int i; 382 383 bpf_for(i, 0, 100) 384 arr[i] *= i; 385 386 return 0; 387 } 388 389 SEC("?syscall") 390 __success __log_level(2) 391 int arg_tag_ctx_syscall_bpf_for(void *ctx) 392 { 393 return syscall_array_bpf_for(ctx); 394 } 395 396 SEC("syscall") 397 __auxiliary 398 int syscall_tailcall_target(void *ctx) 399 { 400 return syscall_array_bpf_for(ctx); 401 } 402 403 struct { 404 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 405 __uint(max_entries, 1); 406 __uint(key_size, sizeof(__u32)); 407 __array(values, int (void *)); 408 } syscall_prog_array SEC(".maps") = { 409 .values = { 410 [0] = (void *)&syscall_tailcall_target, 411 }, 412 }; 413 414 SEC("?syscall") 415 __success __log_level(2) 416 int arg_tag_ctx_syscall_tailcall(void *ctx) 417 { 418 bpf_tail_call(ctx, &syscall_prog_array, 0); 419 return 0; 420 } 421 422 SEC("?syscall") 423 __failure __log_level(2) 424 __msg("dereference of modified ctx ptr R1 off=8 disallowed") 425 int arg_tag_ctx_syscall_tailcall_fixed_off_bad(void *ctx) 426 { 427 char *p = ctx; 428 429 p += 8; 430 bpf_tail_call(p, &syscall_prog_array, 0); 431 return 0; 432 } 433 434 SEC("?syscall") 435 __failure __log_level(2) 436 __msg("variable ctx access var_off=(0x0; 0x4) disallowed") 437 int arg_tag_ctx_syscall_tailcall_var_off_bad(void *ctx) 438 { 439 __u64 off = bpf_get_prandom_u32(); 440 char *p = ctx; 441 442 off &= 4; 443 p += off; 444 bpf_tail_call(p, &syscall_prog_array, 0); 445 return 0; 446 } 447 448 SEC("?syscall") 449 __failure __log_level(2) 450 __msg("dereference of modified ctx ptr R1 off=8 disallowed") 451 int arg_tag_ctx_syscall_fixed_off_bad(void *ctx) 452 { 453 char *p = ctx; 454 455 p += 8; 456 return subprog_ctx_tag(p); 457 } 458 459 SEC("?syscall") 460 __failure __log_level(2) 461 __msg("variable ctx access var_off=(0x0; 0x4) disallowed") 462 int arg_tag_ctx_syscall_var_off_bad(void *ctx) 463 { 464 __u64 off = bpf_get_prandom_u32(); 465 char *p = ctx; 466 467 off &= 4; 468 p += off; 469 return subprog_ctx_tag(p); 470 } 471 472 __weak int subprog_dynptr(struct bpf_dynptr *dptr) 473 { 474 long *d, t, buf[1] = {}; 475 476 d = bpf_dynptr_data(dptr, 0, sizeof(long)); 477 if (!d) 478 return 0; 479 480 t = *d + 1; 481 482 d = bpf_dynptr_slice(dptr, 0, &buf, sizeof(long)); 483 if (!d) 484 return t; 485 486 t = *d + 2; 487 488 return t; 489 } 490 491 SEC("?xdp") 492 __success __log_level(2) 493 int arg_tag_dynptr(struct xdp_md *ctx) 494 { 495 struct bpf_dynptr dptr; 496 497 bpf_dynptr_from_xdp(ctx, 0, &dptr); 498 499 return subprog_dynptr(&dptr); 500 } 501 502 __weak 503 void foo(void) 504 { 505 } 506 507 SEC("?tc") 508 __failure __msg("R0 !read_ok") 509 int return_from_void_global(struct __sk_buff *skb) 510 { 511 foo(); 512 513 asm volatile( 514 "r1 = r0;" 515 ::: 516 ); 517 518 return 0; 519 } 520 521 char _license[] SEC("license") = "GPL"; 522