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_misc.h" 7 #include "xdp_metadata.h" 8 #include "bpf_kfuncs.h" 9 10 int arr[1]; 11 int unkn_idx; 12 const volatile bool call_dead_subprog = false; 13 14 __noinline long global_bad(void) 15 { 16 return arr[unkn_idx]; /* BOOM */ 17 } 18 19 __noinline long global_good(void) 20 { 21 return arr[0]; 22 } 23 24 __noinline long global_calls_bad(void) 25 { 26 return global_good() + global_bad() /* does BOOM indirectly */; 27 } 28 29 __noinline long global_calls_good_only(void) 30 { 31 return global_good(); 32 } 33 34 __noinline long global_dead(void) 35 { 36 return arr[0] * 2; 37 } 38 39 SEC("?raw_tp") 40 __success __log_level(2) 41 /* main prog is validated completely first */ 42 __msg("('global_calls_good_only') is global and assumed valid.") 43 /* eventually global_good() is transitively validated as well */ 44 __msg("Validating global_good() func") 45 __msg("('global_good') is safe for any args that match its prototype") 46 int chained_global_func_calls_success(void) 47 { 48 int sum = 0; 49 50 if (call_dead_subprog) 51 sum += global_dead(); 52 return global_calls_good_only() + sum; 53 } 54 55 SEC("?raw_tp") 56 __failure __log_level(2) 57 /* main prog validated successfully first */ 58 __msg("('global_calls_bad') is global and assumed valid.") 59 /* eventually we validate global_bad() and fail */ 60 __msg("Validating global_bad() func") 61 __msg("math between map_value pointer and register") /* BOOM */ 62 int chained_global_func_calls_bad(void) 63 { 64 return global_calls_bad(); 65 } 66 67 /* do out of bounds access forcing verifier to fail verification if this 68 * global func is called 69 */ 70 __noinline int global_unsupp(const int *mem) 71 { 72 if (!mem) 73 return 0; 74 return mem[100]; /* BOOM */ 75 } 76 77 const volatile bool skip_unsupp_global = true; 78 79 SEC("?raw_tp") 80 __success 81 int guarded_unsupp_global_called(void) 82 { 83 if (!skip_unsupp_global) 84 return global_unsupp(NULL); 85 return 0; 86 } 87 88 SEC("?raw_tp") 89 __failure __log_level(2) 90 __msg("Func#1 ('global_unsupp') is global and assumed valid.") 91 __msg("Validating global_unsupp() func#1...") 92 __msg("value is outside of the allowed memory range") 93 int unguarded_unsupp_global_called(void) 94 { 95 int x = 0; 96 97 return global_unsupp(&x); 98 } 99 100 long stack[128]; 101 102 __weak int subprog_nullable_ptr_bad(int *p) 103 { 104 return (*p) * 2; /* bad, missing null check */ 105 } 106 107 SEC("?raw_tp") 108 __failure __log_level(2) 109 __msg("invalid mem access 'mem_or_null'") 110 int arg_tag_nullable_ptr_fail(void *ctx) 111 { 112 int x = 42; 113 114 return subprog_nullable_ptr_bad(&x); 115 } 116 117 __noinline __weak int subprog_nonnull_ptr_good(int *p1 __arg_nonnull, int *p2 __arg_nonnull) 118 { 119 return (*p1) * (*p2); /* good, no need for NULL checks */ 120 } 121 122 int x = 47; 123 124 SEC("?raw_tp") 125 __success __log_level(2) 126 int arg_tag_nonnull_ptr_good(void *ctx) 127 { 128 int y = 74; 129 130 return subprog_nonnull_ptr_good(&x, &y); 131 } 132 133 /* this global subprog can be now called from many types of entry progs, each 134 * with different context type 135 */ 136 __weak int subprog_ctx_tag(void *ctx __arg_ctx) 137 { 138 return bpf_get_stack(ctx, stack, sizeof(stack), 0); 139 } 140 141 SEC("?raw_tp") 142 __success __log_level(2) 143 int arg_tag_ctx_raw_tp(void *ctx) 144 { 145 return subprog_ctx_tag(ctx); 146 } 147 148 SEC("?tp") 149 __success __log_level(2) 150 int arg_tag_ctx_tp(void *ctx) 151 { 152 return subprog_ctx_tag(ctx); 153 } 154 155 SEC("?kprobe") 156 __success __log_level(2) 157 int arg_tag_ctx_kprobe(void *ctx) 158 { 159 return subprog_ctx_tag(ctx); 160 } 161 162 __weak int subprog_dynptr(struct bpf_dynptr *dptr) 163 { 164 long *d, t, buf[1] = {}; 165 166 d = bpf_dynptr_data(dptr, 0, sizeof(long)); 167 if (!d) 168 return 0; 169 170 t = *d + 1; 171 172 d = bpf_dynptr_slice(dptr, 0, &buf, sizeof(long)); 173 if (!d) 174 return t; 175 176 t = *d + 2; 177 178 return t; 179 } 180 181 SEC("?xdp") 182 __success __log_level(2) 183 int arg_tag_dynptr(struct xdp_md *ctx) 184 { 185 struct bpf_dynptr dptr; 186 187 bpf_dynptr_from_xdp(ctx, 0, &dptr); 188 189 return subprog_dynptr(&dptr); 190 } 191 192 char _license[] SEC("license") = "GPL"; 193