On Wed, Aug 17, 2022 at 11:43 AM Daniel Xu <dxu@xxxxxxxxx> wrote: > > +/* Check writes into `struct nf_conn` */ > +int nf_conntrack_btf_struct_access(struct bpf_verifier_log *log, > + const struct btf *btf, > + const struct btf_type *t, int off, > + int size, enum bpf_access_type atype, > + u32 *next_btf_id, > + enum bpf_type_flag *flag) > +{ > + const struct btf_type *nct = READ_ONCE(nf_conn_type); > + s32 type_id; > + size_t end; > + > + if (!nct) { > + type_id = btf_find_by_name_kind(btf, "nf_conn", BTF_KIND_STRUCT); > + if (type_id < 0) > + return -EINVAL; > + > + nct = btf_type_by_id(btf, type_id); > + WRITE_ONCE(nf_conn_type, nct); > + } > + > + if (t != nct) { > + bpf_log(log, "only read is supported\n"); > + return -EACCES; > + } > + > + switch (off) { > +#if defined(CONFIG_NF_CONNTRACK_MARK) > + case offsetof(struct nf_conn, mark): > + end = offsetofend(struct nf_conn, mark); > + break; > +#endif > + default: > + bpf_log(log, "no write support to nf_conn at off %d\n", off); > + return -EACCES; > + } > + > + if (off + size > end) { > + bpf_log(log, > + "write access at off %d with size %d beyond the member of nf_conn ended at %zu\n", > + off, size, end); > + return -EACCES; > + } > + > + return NOT_INIT; Took me a long time to realize that this is a copy-paste from net/ipv4/bpf_tcp_ca.c. It's not wrong, but misleading. When atype == BPF_READ the return value from btf_struct_access should only be error<0, SCALAR_VALUE, PTR_TO_BTF_ID. For atype == BPF_WRITE we should probably standardize on error<0, or 0. The NOT_INIT happens to be zero, but explicit 0 is cleaner to avoid confusion that this is somehow enum bpf_reg_type. Martin, since you've added this code in bpf_tcp_ca, wdyt?