On Mon, Aug 20, 2018 at 1:47 AM Song Liu <liu.song....@gmail.com> wrote: > > On Thu, Aug 16, 2018 at 4:14 PM, Petar Penkov <ppen...@google.com> wrote: > > On Thu, Aug 16, 2018 at 3:40 PM, Song Liu <liu.song....@gmail.com> wrote: > >> > >> On Thu, Aug 16, 2018 at 9:44 AM, Petar Penkov <peterpenko...@gmail.com> > >> wrote: > >> > From: Petar Penkov <ppen...@google.com> > >> > > >> > Adds a hook for programs of type BPF_PROG_TYPE_FLOW_DISSECTOR and > >> > attach type BPF_FLOW_DISSECTOR that is executed in the flow dissector > >> > path. The BPF program is kept as a global variable so it is > >> > accessible to all flow dissectors. > >> > > >> > Signed-off-by: Petar Penkov <ppen...@google.com> > >> > Signed-off-by: Willem de Bruijn <will...@google.com>
> >> > @@ -658,6 +698,42 @@ bool __skb_flow_dissect(const struct sk_buff *skb, > >> > FLOW_DISSECTOR_KEY_BASIC, > >> > target_container); > >> > > >> > + rcu_read_lock(); > >> > + attached = rcu_dereference(flow_dissector_prog); > >> > + if (attached) { > >> > + /* Note that even though the const qualifier is discarded > >> > + * throughout the execution of the BPF program, all > >> > changes(the > >> > + * control block) are reverted after the BPF program > >> > returns. > >> > + * Therefore, __skb_flow_dissect does not alter the skb. > >> > + */ > >> > + struct bpf_flow_dissect_cb *cb; > >> > + u8 cb_saved[BPF_SKB_CB_LEN]; > >> > + u32 result; > >> > + > >> > + cb = (struct bpf_flow_dissect_cb *)(bpf_skb_cb((struct > >> > sk_buff *)skb)); > >> > + > >> > + /* Save Control Block */ > >> > + memcpy(cb_saved, cb, sizeof(cb_saved)); > >> > + memset(cb, 0, sizeof(cb_saved)); > >> > + > >> > + /* Pass parameters to the BPF program */ > >> > + cb->nhoff = nhoff; > >> > + cb->target_container = target_container; > >> > + cb->flow_dissector = flow_dissector; > >> > + > >> > + bpf_compute_data_pointers((struct sk_buff *)skb); > >> > + result = BPF_PROG_RUN(attached, skb); > >> > + > >> > + /* Restore state */ > >> > + memcpy(cb, cb_saved, sizeof(cb_saved)); > >> > + > >> > + key_control->thoff = min_t(u16, key_control->thoff, > >> > + skb ? skb->len : hlen); > >> > + rcu_read_unlock(); > >> > + return result == BPF_OK; > >> > + } > >> > >> If the BPF program cannot handle certain protocol, shall we fall back > >> to the built-in logic? Otherwise, all BPF programs need to have some > >> code for all protocols. > >> > >> Song > > > > I believe that if we fall back to the built-in logic we lose all security > > guarantees from BPF and this is why the code does not support > > fall back. > > > > Petar > > I am not really sure we are on the same page. I am proposing 3 > different return values from BPF_PROG_RUN(), and they should be > handled as > > 1. result == BPF_OK => return true; > 2. result == BPF_DROP => return false; > 3. result == something else => fall back. > > Does this proposal make any sense? > > Thanks, > Song It certainly makes sense. We debated it initially, as well. In the short term, it allows for simpler BPF programs, as they can off-load some protocols to the C implementation. But the RFC patchset already implements most protocols in BPF. I had not expected that when we started out. Eventually, I think it is preferable to just deprecate the C implementation. Which is not possible if we make this opt-out a part of the BPF flow dissector interface. There is also the lesser issue that a buggy BPF program might accidentally pass the third value and unknowing open itself up to the large attack surface. Without this option, the security audit is much simpler.