@@ -75,6 +75,7 @@
#define KF_ITER_NEW (1 << 8) /* kfunc implements BPF iter constructor */
#define KF_ITER_NEXT (1 << 9) /* kfunc implements BPF iter next method */
#define KF_ITER_DESTROY (1 << 10) /* kfunc implements BPF iter destructor */
+#define KF_THROW (1 << 11) /* kfunc may throw a BPF exception */
/*
* Tag marking a kernel function as a kfunc. This is meant to minimize the
@@ -9454,6 +9454,11 @@ static bool is_kfunc_arg_kptr_get(struct bpf_kfunc_call_arg_meta *meta, int arg)
return arg == 0 && (meta->kfunc_flags & KF_KPTR_GET);
}
+static bool is_kfunc_throwing(struct bpf_kfunc_call_arg_meta *meta)
+{
+ return meta->kfunc_flags & KF_THROW;
+}
+
static bool __kfunc_param_match_suffix(const struct btf *btf,
const struct btf_param *arg,
const char *suffix)
@@ -10813,11 +10818,14 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
}
}
- if (meta.btf == btf_vmlinux && meta.func_id == special_kfunc_list[KF_bpf_throw]) {
+ if (is_kfunc_throwing(&meta) ||
+ (meta.btf == btf_vmlinux && meta.func_id == special_kfunc_list[KF_bpf_throw])) {
err = mark_chain_throw(env, insn_idx);
if (err < 0)
return err;
- return 1;
+ /* Halt exploration only for bpf_throw */
+ if (!is_kfunc_throwing(&meta))
+ return 1;
}
for (i = 0; i < CALLER_SAVED_REGS; i++)
@@ -766,6 +766,16 @@ __bpf_kfunc static u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused
return arg;
}
+__bpf_kfunc notrace void bpf_kfunc_call_test_always_throws(void)
+{
+ bpf_throw();
+}
+
+__bpf_kfunc notrace void bpf_kfunc_call_test_never_throws(void)
+{
+ return;
+}
+
__diag_pop();
BTF_SET8_START(bpf_test_modify_return_ids)
@@ -806,6 +816,8 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test_ref, KF_TRUSTED_ARGS | KF_RCU)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_destructive, KF_DESTRUCTIVE)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset)
+BTF_ID_FLAGS(func, bpf_kfunc_call_test_always_throws, KF_THROW)
+BTF_ID_FLAGS(func, bpf_kfunc_call_test_never_throws, KF_THROW)
BTF_SET8_END(test_sk_check_kfunc_ids)
static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size,
Add KF_THROW annotation to kfuncs to indicate that they may throw. This is mostly for testing for now, but in the future it could be used by kfuncs to throw on invalid arguments or invalid conditions based on their input arguments, causing the program to abort, and simplify the overall user experience of kfuncs for the happy case, without having to deal with corner cases that never occur at runtime. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> --- include/linux/btf.h | 1 + kernel/bpf/verifier.c | 12 ++++++++++-- net/bpf/test_run.c | 12 ++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-)