Commit 51081a3
bpf: track changes_pkt_data property for global functions
When processing calls to certain helpers, verifier invalidates all
packet pointers in a current state. For example, consider the
following program:
__attribute__((__noinline__))
long skb_pull_data(struct __sk_buff *sk, __u32 len)
{
return bpf_skb_pull_data(sk, len);
}
SEC("tc")
int test_invalidate_checks(struct __sk_buff *sk)
{
int *p = (void *)(long)sk->data;
if ((void *)(p + 1) > (void *)(long)sk->data_end) return TCX_DROP;
skb_pull_data(sk, 0);
*p = 42;
return TCX_PASS;
}
After a call to bpf_skb_pull_data() the pointer 'p' can't be used
safely. See function filter.c:bpf_helper_changes_pkt_data() for a list
of such helpers.
At the moment verifier invalidates packet pointers when processing
helper function calls, and does not traverse global sub-programs when
processing calls to global sub-programs. This means that calls to
helpers done from global sub-programs do not invalidate pointers in
the caller state. E.g. the program above is unsafe, but is not
rejected by verifier.
This commit fixes the omission by computing field
bpf_subprog_info->changes_pkt_data for each sub-program before main
verification pass.
changes_pkt_data should be set if:
- subprogram calls helper for which bpf_helper_changes_pkt_data
returns true;
- subprogram calls a global function,
for which bpf_subprog_info->changes_pkt_data should be set.
The verifier.c:check_cfg() pass is modified to compute this
information. The commit relies on depth first instruction traversal
done by check_cfg() and absence of recursive function calls:
- check_cfg() would eventually visit every call to subprogram S in a
state when S is fully explored;
- when S is fully explored:
- every direct helper call within S is explored
(and thus changes_pkt_data is set if needed);
- every call to subprogram S1 called by S was visited with S1 fully
explored (and thus S inherits changes_pkt_data from S1).
The downside of such approach is that dead code elimination is not
taken into account: if a helper call inside global function is dead
because of current configuration, verifier would conservatively assume
that the call occurs for the purpose of the changes_pkt_data
computation.
Reported-by: Nick Zavaritsky <mejedi@gmail.com>
Closes: https://lore.kernel.org/bpf/0498CA22-5779-4767-9C0C-A9515CEA711F@gmail.com/
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20241210041100.1898468-4-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>1 parent b238e18 commit 51081a3
2 files changed
+32
-1
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
659 | 659 | | |
660 | 660 | | |
661 | 661 | | |
| 662 | + | |
662 | 663 | | |
663 | 664 | | |
664 | 665 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10042 | 10042 | | |
10043 | 10043 | | |
10044 | 10044 | | |
| 10045 | + | |
| 10046 | + | |
10045 | 10047 | | |
10046 | 10048 | | |
10047 | 10049 | | |
| |||
16246 | 16248 | | |
16247 | 16249 | | |
16248 | 16250 | | |
| 16251 | + | |
| 16252 | + | |
| 16253 | + | |
| 16254 | + | |
| 16255 | + | |
| 16256 | + | |
| 16257 | + | |
| 16258 | + | |
| 16259 | + | |
| 16260 | + | |
| 16261 | + | |
| 16262 | + | |
| 16263 | + | |
| 16264 | + | |
| 16265 | + | |
| 16266 | + | |
| 16267 | + | |
| 16268 | + | |
| 16269 | + | |
| 16270 | + | |
| 16271 | + | |
| 16272 | + | |
| 16273 | + | |
16249 | 16274 | | |
16250 | 16275 | | |
16251 | 16276 | | |
| |||
16379 | 16404 | | |
16380 | 16405 | | |
16381 | 16406 | | |
| 16407 | + | |
16382 | 16408 | | |
16383 | 16409 | | |
16384 | 16410 | | |
| |||
16390 | 16416 | | |
16391 | 16417 | | |
16392 | 16418 | | |
| 16419 | + | |
16393 | 16420 | | |
16394 | | - | |
| 16421 | + | |
| 16422 | + | |
16395 | 16423 | | |
16396 | 16424 | | |
16397 | 16425 | | |
| |||
16708 | 16736 | | |
16709 | 16737 | | |
16710 | 16738 | | |
| 16739 | + | |
| 16740 | + | |
16711 | 16741 | | |
16712 | 16742 | | |
16713 | 16743 | | |
| |||
0 commit comments