Re: [PATCH bpf 3/4] bpf: track changes_pkt_data property for global functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Dec 9, 2024 at 9:57 AM Eduard Zingerman <eddyz87@xxxxxxxxx> wrote:
>
> On Mon, 2024-12-09 at 08:53 -0800, Alexei Starovoitov wrote:
>
> [...]
>
> > >
> > >     // tc_bpf2bpf.c
> > >     __noinline                             freplace
> > >     int subprog_tc(struct __sk_buff *skb) <--------.
> > >     {                                              |
> > >         int ret = 1;                               |
> > >                                                    |
> > >         __sink(skb);                               |
> > >         __sink(ret);                               |
> > >         return ret;                                |
> > >     }                                              |
> > >                                                    |
> > >     SEC("tc")                                      |
> > >     int entry_tc(struct __sk_buff *skb)            |
> > >     {                                              |
> > >         return subprog_tc(skb);                    |
> > >     }                                              |
> > >                                                    |
> > >     // tailcall_freplace.c                         |
> > >     struct {                                       |
> > >         __uint(type, BPF_MAP_TYPE_PROG_ARRAY);     |
> > >         __uint(max_entries, 1);                    |
> > >         __uint(key_size, sizeof(__u32));           |
> > >         __uint(value_size, sizeof(__u32));         |
> > >     } jmp_table SEC(".maps");                      |
> > >                                                    |
> > >     int count = 0;                                 |
> > >                                                    |
> > >     SEC("freplace")                                |
> > >     int entry_freplace(struct __sk_buff *skb) -----'
> > >     {
> > >         count++;
> > >         bpf_tail_call_static(skb, &jmp_table, 0);
> > >         return count;
> > >     }
> >
> > hmm. none of the above changes pkt_data, so it should be allowed.
> > The prog doesn't read skb->data either.
> > So I don't quite see the problem.
>
> The problem is when I use simplified rule: "every tail call changes packet data",
> as a substitute for proper map content effects tracking.
>
> If map content effects are tracked, there should be no problems
> verifying this program. However, that can't be done in check_cfg(),
> as it does not track register values, and register value is needed to
> identify the map.

We don't need data flow analysis and R1 tracking.

We could do the following rule:
if prog has a tail call and any prog array map in prog->aux->used_maps
calls into prog with adjust_pkt_data assume that this prog
also adjusts pkt_data.

> Hence, mechanics with "in-line" global sub-program
> traversal is needed (as described by Andrii):
> - during a regular verification pass get to a global sub-program call:
>   - if sub-program had not been visited yet, verify it completely
>     and compute changes_pkt_data effect;
>   - continue from the call-site using the computed effect;
> - during a regular verification pass get to a tail call:
>   - check the map pointed to by R1 to see whether it has
>     changes_pkt_data effect.

I don't think we should be adding all that logic when a much simpler
rule (as described above) is good enough.

Also either inline global sub-prog traversal or the simple rule above
both suffer from the following issue:
in case prog_array is empty map->changes_pkt_data will be false.
It will be set to true only when the first
prog_fd_array_get_ptr()->bpf_prog_map_compatible()
will record changes_pkt_data from the first prog inserted in prog_array.

So main prog reading skb->data after calling subprog that tail_calls
somewhere should assume that skb->data is invalidated.

That's pretty much your rule "every tail call changes packet data".

I think we can go with this simplest approach as well.
The test you mentioned have to be adjusted. Not a big deal.

Or we can do:
"if prog_array empty assume adjusts_pkt_data == true,
otherwise adj_pkt_data | = for each map in used_maps {
map->owner.adj_pkt_data }"

The fancy inline global subprog traversal would have to have the same
"simple" (or call it dumb) rule.
So at the end both inline or check_cfg are not accurate at all,
but check_cfg approach is so much simpler.





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux