1// SPDX-License-Identifier: GPL-2.0 2#include <vmlinux.h> 3#include <bpf/bpf_tracing.h> 4#include <bpf/bpf_helpers.h> 5#include <bpf/bpf_core_read.h> 6 7#include "bpf_misc.h" 8#include "bpf_experimental.h" 9 10extern void bpf_rcu_read_lock(void) __ksym; 11 12#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8))) 13 14struct foo { 15 struct bpf_rb_node node; 16}; 17 18struct hmap_elem { 19 struct bpf_timer timer; 20}; 21 22struct { 23 __uint(type, BPF_MAP_TYPE_HASH); 24 __uint(max_entries, 64); 25 __type(key, int); 26 __type(value, struct hmap_elem); 27} hmap SEC(".maps"); 28 29private(A) struct bpf_spin_lock lock; 30private(A) struct bpf_rb_root rbtree __contains(foo, node); 31 32__noinline void *exception_cb_bad_ret_type(u64 cookie) 33{ 34 return NULL; 35} 36 37__noinline int exception_cb_bad_arg_0(void) 38{ 39 return 0; 40} 41 42__noinline int exception_cb_bad_arg_2(int a, int b) 43{ 44 return 0; 45} 46 47__noinline int exception_cb_ok_arg_small(int a) 48{ 49 return 0; 50} 51 52SEC("?tc") 53__exception_cb(exception_cb_bad_ret_type) 54__failure __msg("Global function exception_cb_bad_ret_type() doesn't return scalar.") 55int reject_exception_cb_type_1(struct __sk_buff *ctx) 56{ 57 bpf_throw(0); 58 return 0; 59} 60 61SEC("?tc") 62__exception_cb(exception_cb_bad_arg_0) 63__failure __msg("exception cb only supports single integer argument") 64int reject_exception_cb_type_2(struct __sk_buff *ctx) 65{ 66 bpf_throw(0); 67 return 0; 68} 69 70SEC("?tc") 71__exception_cb(exception_cb_bad_arg_2) 72__failure __msg("exception cb only supports single integer argument") 73int reject_exception_cb_type_3(struct __sk_buff *ctx) 74{ 75 bpf_throw(0); 76 return 0; 77} 78 79SEC("?tc") 80__exception_cb(exception_cb_ok_arg_small) 81__success 82int reject_exception_cb_type_4(struct __sk_buff *ctx) 83{ 84 bpf_throw(0); 85 return 0; 86} 87 88__noinline 89static int timer_cb(void *map, int *key, struct bpf_timer *timer) 90{ 91 bpf_throw(0); 92 return 0; 93} 94 95SEC("?tc") 96__failure __msg("cannot be called from callback subprog") 97int reject_async_callback_throw(struct __sk_buff *ctx) 98{ 99 struct hmap_elem *elem; 100 101 elem = bpf_map_lookup_elem(&hmap, &(int){0}); 102 if (!elem) 103 return 0; 104 return bpf_timer_set_callback(&elem->timer, timer_cb); 105} 106 107__noinline static int subprog_lock(struct __sk_buff *ctx) 108{ 109 volatile int ret = 0; 110 111 bpf_spin_lock(&lock); 112 if (ctx->len) 113 bpf_throw(0); 114 return ret; 115} 116 117SEC("?tc") 118__failure __msg("function calls are not allowed while holding a lock") 119int reject_with_lock(void *ctx) 120{ 121 bpf_spin_lock(&lock); 122 bpf_throw(0); 123 return 0; 124} 125 126SEC("?tc") 127__failure __msg("function calls are not allowed while holding a lock") 128int reject_subprog_with_lock(void *ctx) 129{ 130 return subprog_lock(ctx); 131} 132 133SEC("?tc") 134__failure __msg("bpf_rcu_read_unlock is missing") 135int reject_with_rcu_read_lock(void *ctx) 136{ 137 bpf_rcu_read_lock(); 138 bpf_throw(0); 139 return 0; 140} 141 142__noinline static int throwing_subprog(struct __sk_buff *ctx) 143{ 144 if (ctx->len) 145 bpf_throw(0); 146 return 0; 147} 148 149SEC("?tc") 150__failure __msg("bpf_rcu_read_unlock is missing") 151int reject_subprog_with_rcu_read_lock(void *ctx) 152{ 153 bpf_rcu_read_lock(); 154 return throwing_subprog(ctx); 155} 156 157static bool rbless(struct bpf_rb_node *n1, const struct bpf_rb_node *n2) 158{ 159 bpf_throw(0); 160 return true; 161} 162 163SEC("?tc") 164__failure __msg("function calls are not allowed while holding a lock") 165int reject_with_rbtree_add_throw(void *ctx) 166{ 167 struct foo *f; 168 169 f = bpf_obj_new(typeof(*f)); 170 if (!f) 171 return 0; 172 bpf_spin_lock(&lock); 173 bpf_rbtree_add(&rbtree, &f->node, rbless); 174 bpf_spin_unlock(&lock); 175 return 0; 176} 177 178SEC("?tc") 179__failure __msg("Unreleased reference") 180int reject_with_reference(void *ctx) 181{ 182 struct foo *f; 183 184 f = bpf_obj_new(typeof(*f)); 185 if (!f) 186 return 0; 187 bpf_throw(0); 188 return 0; 189} 190 191__noinline static int subprog_ref(struct __sk_buff *ctx) 192{ 193 struct foo *f; 194 195 f = bpf_obj_new(typeof(*f)); 196 if (!f) 197 return 0; 198 bpf_throw(0); 199 return 0; 200} 201 202__noinline static int subprog_cb_ref(u32 i, void *ctx) 203{ 204 bpf_throw(0); 205 return 0; 206} 207 208SEC("?tc") 209__failure __msg("Unreleased reference") 210int reject_with_cb_reference(void *ctx) 211{ 212 struct foo *f; 213 214 f = bpf_obj_new(typeof(*f)); 215 if (!f) 216 return 0; 217 bpf_loop(5, subprog_cb_ref, NULL, 0); 218 bpf_obj_drop(f); 219 return 0; 220} 221 222SEC("?tc") 223__failure __msg("cannot be called from callback") 224int reject_with_cb(void *ctx) 225{ 226 bpf_loop(5, subprog_cb_ref, NULL, 0); 227 return 0; 228} 229 230SEC("?tc") 231__failure __msg("Unreleased reference") 232int reject_with_subprog_reference(void *ctx) 233{ 234 return subprog_ref(ctx) + 1; 235} 236 237__noinline int throwing_exception_cb(u64 c) 238{ 239 bpf_throw(0); 240 return c; 241} 242 243__noinline int exception_cb1(u64 c) 244{ 245 return c; 246} 247 248__noinline int exception_cb2(u64 c) 249{ 250 return c; 251} 252 253static __noinline int static_func(struct __sk_buff *ctx) 254{ 255 return exception_cb1(ctx->tstamp); 256} 257 258__noinline int global_func(struct __sk_buff *ctx) 259{ 260 return exception_cb1(ctx->tstamp); 261} 262 263SEC("?tc") 264__exception_cb(throwing_exception_cb) 265__failure __msg("cannot be called from callback subprog") 266int reject_throwing_exception_cb(struct __sk_buff *ctx) 267{ 268 return 0; 269} 270 271SEC("?tc") 272__exception_cb(exception_cb1) 273__failure __msg("cannot call exception cb directly") 274int reject_exception_cb_call_global_func(struct __sk_buff *ctx) 275{ 276 return global_func(ctx); 277} 278 279SEC("?tc") 280__exception_cb(exception_cb1) 281__failure __msg("cannot call exception cb directly") 282int reject_exception_cb_call_static_func(struct __sk_buff *ctx) 283{ 284 return static_func(ctx); 285} 286 287SEC("?tc") 288__exception_cb(exception_cb1) 289__exception_cb(exception_cb2) 290__failure __msg("multiple exception callback tags for main subprog") 291int reject_multiple_exception_cb(struct __sk_buff *ctx) 292{ 293 bpf_throw(0); 294 return 16; 295} 296 297__noinline int exception_cb_bad_ret(u64 c) 298{ 299 return c; 300} 301 302SEC("?fentry/bpf_check") 303__exception_cb(exception_cb_bad_ret) 304__failure __msg("At program exit the register R0 has unknown scalar value should") 305int reject_set_exception_cb_bad_ret1(void *ctx) 306{ 307 return 0; 308} 309 310SEC("?fentry/bpf_check") 311__failure __msg("At program exit the register R1 has smin=64 smax=64 should") 312int reject_set_exception_cb_bad_ret2(void *ctx) 313{ 314 bpf_throw(64); 315 return 0; 316} 317 318__noinline static int loop_cb1(u32 index, int *ctx) 319{ 320 bpf_throw(0); 321 return 0; 322} 323 324__noinline static int loop_cb2(u32 index, int *ctx) 325{ 326 bpf_throw(0); 327 return 0; 328} 329 330SEC("?tc") 331__failure __msg("cannot be called from callback") 332int reject_exception_throw_cb(struct __sk_buff *ctx) 333{ 334 bpf_loop(5, loop_cb1, NULL, 0); 335 return 0; 336} 337 338SEC("?tc") 339__failure __msg("cannot be called from callback") 340int reject_exception_throw_cb_diff(struct __sk_buff *ctx) 341{ 342 if (ctx->protocol) 343 bpf_loop(5, loop_cb1, NULL, 0); 344 else 345 bpf_loop(5, loop_cb2, NULL, 0); 346 return 0; 347} 348 349char _license[] SEC("license") = "GPL"; 350