-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incomplete read marks debug #8655
Open
eddyz87
wants to merge
2
commits into
kernel-patches:bpf-next_base
Choose a base branch
from
eddyz87:incomplete-read-marks-debug
base: bpf-next_base
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Incomplete read marks debug #8655
eddyz87
wants to merge
2
commits into
kernel-patches:bpf-next_base
from
eddyz87:incomplete-read-marks-debug
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Suppose the verifier state exploration graph looks as follows: .-> A --. Suppose: | | | - state A is at iterator 'next'; | v v - path A -> B -> A is verified first; '-- B C - path A -> C is verified next; - B does not impose a read mark for register R1; - C imposes a read mark for register R1; Under such conditions: - when B is explored and A is identified as its loop entry, the read marks are copied from A to B by propagate_liveness(), but these marks do not include R1; - when C is explored, the read mark for R1 is propagated to A, but not to B. - at this point, state A has its branch count at zero, but state B has incomplete read marks. The same logic applies to precision marks. This means that states with a loop entry can have incomplete read and precision marks, regardless of whether the loop entry itself has branches. The current verification logic does not account for this. An example of an unsafe program accepted by the verifier is the selftest included in the next patch. Fix this by removing bpf_verifier_state->branches checks for loop entries in clean_live_states() and is_state_visited(). Verification performance impact for selftests and sched_ext: ========= selftests: master vs patch ========= File Program States (A) States (B) States (DIFF) ---------------------------------- ----------------- ---------- ---------- ------------- iters.bpf.o clean_live_states 66 67 +1 (+1.52%) verifier_iterating_callbacks.bpf.o cond_break2 10 13 +3 (+30.00%) Total progs: 3579 Old success: 2061 New success: 2061 States diff min: 0.00% States diff max: 30.00% 0 .. 5 %: 3578 30 .. 35 %: 1 ========= sched_ext: master vs patch ========= File Program States (A) States (B) States (DIFF) -------------- ---------------- ---------- ---------- ------------- bpf.bpf.o layered_dispatch 501 516 +15 (+2.99%) bpf.bpf.o layered_dump 237 252 +15 (+6.33%) bpf.bpf.o layered_init 423 432 +9 (+2.13%) bpf.bpf.o p2dq_init 142 144 +2 (+1.41%) scx_pair.bpf.o pair_dispatch 111 138 +27 (+24.32%) scx_qmap.bpf.o qmap_dump 22 30 +8 (+36.36%) scx_qmap.bpf.o qmap_init 654 656 +2 (+0.31%) Total progs: 216 Old success: 186 New success: 186 States diff min: 0.00% States diff max: 36.36% 0 .. 5 %: 213 5 .. 15 %: 1 20 .. 30 %: 1 35 .. 40 %: 1 Fixes: 2a09928 ("bpf: correct loop detection for iterators convergence") Signed-off-by: Eduard Zingerman <[email protected]>
The test case is equivalent of the following C program: 1: r8 = bpf_get_prandom_u32(); 2: r6 = -32; 3: bpf_iter_num_new(&fp[-8], 0, 10); 4: if (unlikely(bpf_get_prandom_u32())) 5: r6 = -31; 6: for (;;) { 7: if (!bpf_iter_num_next(&fp[-8])) 8: break; 9: if (unlikely(bpf_get_prandom_u32())) 10: *(u64 *)(fp + r6) = 7; 11: } 12: bpf_iter_num_destroy(&fp[-8]); 13: return 0; W/o a fix that instructs verifier to ignore branches count for loop entries verification proceeds as follows: - 1-4, state is {r6=-32,fp-8=active}; - 6, checkpoint A is created with {r6=-32,fp-8=active}; - 7, checkpoint B is created with {r6=-32,fp-8=active}, push state {r6=-32,fp-8=active} from 7 to 9; - 8,12,13, {r6=-32,fp-8=drained}, exit; - pop state with {r6=-32,fp-8=active} from 7 to 9; - 9, push state {r6=-32,fp-8=active} from 9 to 10; - 6, checkpoint C is created with {r6=-32,fp-8=active}; - 7, checkpoint A is hit, no precision or propagated for r6 to C; - pop state {r6=-32,fp-8=active} from 9 to 10; - 10, state is {r6=-31,fp-8=active}, r6 is marked as read and precise, these marks are propagated to checkpoints A and B (but not C, as it is not the parent of current state; - 6, {r6=-31,fp-8=active} checkpoint C is hit, because r6 is not marked precise for this checkpoint; - the program is accepted, despite a possibility of unaligned u64 stack access at offset -31. Signed-off-by: Eduard Zingerman <[email protected]>
60e8048
to
3e1f38e
Compare
44c3a1d
to
720c696
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
No description provided.