Skip to content

Commit cafe2c2

Browse files
eddyz87Alexei Starovoitov
authored andcommitted
bpf: widening for callback iterators
Callbacks are similar to open coded iterators, so add imprecise widening logic for callback body processing. This makes callback based loops behave identically to open coded iterators, e.g. allowing to verify programs like below: struct ctx { u32 i; }; int cb(u32 idx, struct ctx* ctx) { ++ctx->i; return 0; } ... struct ctx ctx = { .i = 0 }; bpf_loop(100, cb, &ctx, 0); ... Acked-by: Andrii Nakryiko <[email protected]> Signed-off-by: Eduard Zingerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 958465e commit cafe2c2

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

kernel/bpf/verifier.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9799,9 +9799,10 @@ static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env)
97999799

98009800
static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
98019801
{
9802-
struct bpf_verifier_state *state = env->cur_state;
9802+
struct bpf_verifier_state *state = env->cur_state, *prev_st;
98039803
struct bpf_func_state *caller, *callee;
98049804
struct bpf_reg_state *r0;
9805+
bool in_callback_fn;
98059806
int err;
98069807

98079808
callee = state->frame[state->curframe];
@@ -9856,7 +9857,8 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
98569857
* there function call logic would reschedule callback visit. If iteration
98579858
* converges is_state_visited() would prune that visit eventually.
98589859
*/
9859-
if (callee->in_callback_fn)
9860+
in_callback_fn = callee->in_callback_fn;
9861+
if (in_callback_fn)
98609862
*insn_idx = callee->callsite;
98619863
else
98629864
*insn_idx = callee->callsite + 1;
@@ -9871,6 +9873,24 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
98719873
* bpf_throw, this will be done by copy_verifier_state for extra frames. */
98729874
free_func_state(callee);
98739875
state->frame[state->curframe--] = NULL;
9876+
9877+
/* for callbacks widen imprecise scalars to make programs like below verify:
9878+
*
9879+
* struct ctx { int i; }
9880+
* void cb(int idx, struct ctx *ctx) { ctx->i++; ... }
9881+
* ...
9882+
* struct ctx = { .i = 0; }
9883+
* bpf_loop(100, cb, &ctx, 0);
9884+
*
9885+
* This is similar to what is done in process_iter_next_call() for open
9886+
* coded iterators.
9887+
*/
9888+
prev_st = in_callback_fn ? find_prev_entry(env, state, *insn_idx) : NULL;
9889+
if (prev_st) {
9890+
err = widen_imprecise_scalars(env, prev_st, state);
9891+
if (err)
9892+
return err;
9893+
}
98749894
return 0;
98759895
}
98769896

0 commit comments

Comments
 (0)