On Tue, Jul 26, 2022 at 11:47:04AM -0700, Joanne Koong wrote: > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > index 59a217ca2dfd..0730cd198a7f 100644 > --- a/include/uapi/linux/bpf.h > +++ b/include/uapi/linux/bpf.h > @@ -5241,11 +5241,22 @@ union bpf_attr { > * Description > * Write *len* bytes from *src* into *dst*, starting from *offset* > * into *dst*. > - * *flags* is currently unused. > + * > + * *flags* must be 0 except for skb-type dynptrs. > + * > + * For skb-type dynptrs: > + * * if *offset* + *len* extends into the skb's paged buffers, the user > + * should manually pull the skb with bpf_skb_pull and then try again. bpf_skb_pull_data(). Probably need formatting like, **bpf_skb_pull_data**\ () > + * > + * * *flags* are a combination of **BPF_F_RECOMPUTE_CSUM** (automatically > + * recompute the checksum for the packet after storing the bytes) and > + * **BPF_F_INVALIDATE_HASH** (set *skb*\ **->hash**, *skb*\ > + * **->swhash** and *skb*\ **->l4hash** to 0). > * Return > * 0 on success, -E2BIG if *offset* + *len* exceeds the length > * of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst* > - * is a read-only dynptr or if *flags* is not 0. > + * is a read-only dynptr or if *flags* is not correct, -EAGAIN if for > + * skb-type dynptrs the write extends into the skb's paged buffers. May also mention other negative errors is similar to the bpf_skb_store_bytes() instead of mentioning them one-by-one here. > * > * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len) > * Description > @@ -5253,10 +5264,19 @@ union bpf_attr { > * > * *len* must be a statically known value. The returned data slice > * is invalidated whenever the dynptr is invalidated. > + * > + * For skb-type dynptrs: > + * * if *offset* + *len* extends into the skb's paged buffers, > + * the user should manually pull the skb with bpf_skb_pull and then same here. bpf_skb_pull_data(). > + * try again. > + * > + * * the data slice is automatically invalidated anytime a > + * helper call that changes the underlying packet buffer > + * (eg bpf_skb_pull) is called. > * Return > * Pointer to the underlying dynptr data, NULL if the dynptr is > * read-only, if the dynptr is invalid, or if the offset and length > - * is out of bounds. > + * is out of bounds or in a paged buffer for skb-type dynptrs. > * > * s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len) > * Description > @@ -5331,6 +5351,21 @@ union bpf_attr { > * **-EACCES** if the SYN cookie is not valid. > * > * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin. > + * > + * long bpf_dynptr_from_skb(struct sk_buff *skb, u64 flags, struct bpf_dynptr *ptr) > + * Description > + * Get a dynptr to the data in *skb*. *skb* must be the BPF program > + * context. Depending on program type, the dynptr may be read-only, > + * in which case trying to obtain a direct data slice to it through > + * bpf_dynptr_data will return an error. > + * > + * Calls that change the *skb*'s underlying packet buffer > + * (eg bpf_skb_pull_data) do not invalidate the dynptr, but they do > + * invalidate any data slices associated with the dynptr. > + * > + * *flags* is currently unused, it must be 0 for now. > + * Return > + * 0 on success or -EINVAL if flags is not 0. > */ [ ... ] > @@ -1528,15 +1544,38 @@ static const struct bpf_func_proto bpf_dynptr_read_proto = { > BPF_CALL_5(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src, > u32, len, u64, flags) > { > + enum bpf_dynptr_type type; > int err; > > - if (!dst->data || flags || bpf_dynptr_is_rdonly(dst)) > + if (!dst->data || bpf_dynptr_is_rdonly(dst)) > return -EINVAL; > > err = bpf_dynptr_check_off_len(dst, offset, len); > if (err) > return err; > > + type = bpf_dynptr_get_type(dst); > + > + if (flags) { > + if (type == BPF_DYNPTR_TYPE_SKB) { > + if (flags & ~(BPF_F_RECOMPUTE_CSUM | BPF_F_INVALIDATE_HASH)) nit. The flags is the same as __bpf_skb_store_bytes(). __bpf_skb_store_bytes() can reject as well instead of duplicating the test here. > + return -EINVAL; > + } else { > + return -EINVAL; > + } > + } > + > + if (type == BPF_DYNPTR_TYPE_SKB) { > + struct sk_buff *skb = dst->data; > + > + /* if the data is paged, the caller needs to pull it first */ > + if (dst->offset + offset + len > skb->len - skb->data_len) > + return -EAGAIN; > + > + return __bpf_skb_store_bytes(skb, dst->offset + offset, src, len, > + flags); > + } > +