Skip to content

Commit ae6e3a2

Browse files
kkdwivedianakryiko
authored andcommitted
bpf: Drop special callback reference handling
Logic to prevent callbacks from acquiring new references for the program (i.e. leaving acquired references), and releasing caller references (i.e. those acquired in parent frames) was introduced in commit 9d9d00a ("bpf: Fix reference state management for synchronous callbacks"). This was necessary because back then, the verifier simulated each callback once (that could potentially be executed N times, where N can be zero). This meant that callbacks that left lingering resources or cleared caller resources could do it more than once, operating on undefined state or leaking memory. With the fixes to callback verification in commit ab5cfac ("bpf: verify callbacks as if they are called unknown number of times"), all of this extra logic is no longer necessary. Hence, drop it as part of this commit. Cc: Eduard Zingerman <[email protected]> Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]>
1 parent f6b9a69 commit ae6e3a2

File tree

3 files changed

+11
-39
lines changed

3 files changed

+11
-39
lines changed

include/linux/bpf_verifier.h

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -265,23 +265,10 @@ struct bpf_reference_state {
265265
* is used purely to inform the user of a reference leak.
266266
*/
267267
int insn_idx;
268-
union {
269-
/* There can be a case like:
270-
* main (frame 0)
271-
* cb (frame 1)
272-
* func (frame 3)
273-
* cb (frame 4)
274-
* Hence for frame 4, if callback_ref just stored boolean, it would be
275-
* impossible to distinguish nested callback refs. Hence store the
276-
* frameno and compare that to callback_ref in check_reference_leak when
277-
* exiting a callback function.
278-
*/
279-
int callback_ref;
280-
/* Use to keep track of the source object of a lock, to ensure
281-
* it matches on unlock.
282-
*/
283-
void *ptr;
284-
};
268+
/* Use to keep track of the source object of a lock, to ensure
269+
* it matches on unlock.
270+
*/
271+
void *ptr;
285272
};
286273

287274
struct bpf_retval_range {

kernel/bpf/verifier.c

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,6 @@ static int acquire_reference_state(struct bpf_verifier_env *env, int insn_idx)
13581358
state->refs[new_ofs].type = REF_TYPE_PTR;
13591359
state->refs[new_ofs].id = id;
13601360
state->refs[new_ofs].insn_idx = insn_idx;
1361-
state->refs[new_ofs].callback_ref = state->in_callback_fn ? state->frameno : 0;
13621361

13631362
return id;
13641363
}
@@ -1392,9 +1391,6 @@ static int release_reference_state(struct bpf_func_state *state, int ptr_id)
13921391
if (state->refs[i].type != REF_TYPE_PTR)
13931392
continue;
13941393
if (state->refs[i].id == ptr_id) {
1395-
/* Cannot release caller references in callbacks */
1396-
if (state->in_callback_fn && state->refs[i].callback_ref != state->frameno)
1397-
return -EINVAL;
13981394
if (last_idx && i != last_idx)
13991395
memcpy(&state->refs[i], &state->refs[last_idx],
14001396
sizeof(*state->refs));
@@ -10267,17 +10263,10 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
1026710263
caller->regs[BPF_REG_0] = *r0;
1026810264
}
1026910265

10270-
/* callback_fn frame should have released its own additions to parent's
10271-
* reference state at this point, or check_reference_leak would
10272-
* complain, hence it must be the same as the caller. There is no need
10273-
* to copy it back.
10274-
*/
10275-
if (!callee->in_callback_fn) {
10276-
/* Transfer references to the caller */
10277-
err = copy_reference_state(caller, callee);
10278-
if (err)
10279-
return err;
10280-
}
10266+
/* Transfer references to the caller */
10267+
err = copy_reference_state(caller, callee);
10268+
if (err)
10269+
return err;
1028110270

1028210271
/* for callbacks like bpf_loop or bpf_for_each_map_elem go back to callsite,
1028310272
* there function call logic would reschedule callback visit. If iteration
@@ -10447,14 +10436,12 @@ static int check_reference_leak(struct bpf_verifier_env *env, bool exception_exi
1044710436
bool refs_lingering = false;
1044810437
int i;
1044910438

10450-
if (!exception_exit && state->frameno && !state->in_callback_fn)
10439+
if (!exception_exit && state->frameno)
1045110440
return 0;
1045210441

1045310442
for (i = 0; i < state->acquired_refs; i++) {
1045410443
if (state->refs[i].type != REF_TYPE_PTR)
1045510444
continue;
10456-
if (!exception_exit && state->in_callback_fn && state->refs[i].callback_ref != state->frameno)
10457-
continue;
1045810445
verbose(env, "Unreleased reference id=%d alloc_insn=%d\n",
1045910446
state->refs[i].id, state->refs[i].insn_idx);
1046010447
refs_lingering = true;
@@ -17707,8 +17694,6 @@ static bool refsafe(struct bpf_func_state *old, struct bpf_func_state *cur,
1770717694
return false;
1770817695
switch (old->refs[i].type) {
1770917696
case REF_TYPE_PTR:
17710-
if (old->refs[i].callback_ref != cur->refs[i].callback_ref)
17711-
return false;
1771217697
break;
1771317698
case REF_TYPE_LOCK:
1771417699
if (old->refs[i].ptr != cur->refs[i].ptr)

tools/testing/selftests/bpf/prog_tests/cb_refs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ struct {
1111
const char *prog_name;
1212
const char *err_msg;
1313
} cb_refs_tests[] = {
14-
{ "underflow_prog", "reference has not been acquired before" },
15-
{ "leak_prog", "Unreleased reference" },
14+
{ "underflow_prog", "must point to scalar, or struct with scalar" },
15+
{ "leak_prog", "Possibly NULL pointer passed to helper arg2" },
1616
{ "nested_cb", "Unreleased reference id=4 alloc_insn=2" }, /* alloc_insn=2{4,5} */
1717
{ "non_cb_transfer_ref", "Unreleased reference id=4 alloc_insn=1" }, /* alloc_insn=1{1,2} */
1818
};

0 commit comments

Comments
 (0)