In /proc/net/ipv6_route, we have struct fib6_info { struct fib6_table *fib6_table; ... struct fib6_nh fib6_nh[0]; } struct fib6_nh { struct fib_nh_common nh_common; struct rt6_info **rt6i_pcpu; struct rt6_exception_bucket *rt6i_exception_bucket; }; struct fib_nh_common { ... u8 nhc_gw_family; ... } The access: struct fib6_nh *fib6_nh = &rt->fib6_nh; ... fib6_nh->nh_common.nhc_gw_family ... This patch ensures such an access is handled properly. Signed-off-by: Yonghong Song <yhs@xxxxxx> --- kernel/bpf/btf.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 2c098e6b1acc..dcee5ca0d501 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -3840,6 +3840,31 @@ int btf_struct_access(struct bpf_verifier_log *log, } if (off + size > t->size) { + /* If the last element is a variable size array, we may + * need to relax the rule. + */ + struct btf_array *array_elem; + u32 vlen = btf_type_vlen(t); + u32 last_member_type; + + member = btf_type_member(t); + last_member_type = member[vlen - 1].type; + mtype = btf_type_by_id(btf_vmlinux, last_member_type); + if (!btf_type_is_array(mtype)) + goto error; + + array_elem = (struct btf_array *)(mtype + 1); + if (array_elem->nelems != 0) + goto error; + + elem_type = btf_type_by_id(btf_vmlinux, array_elem->type); + if (!btf_type_is_struct(elem_type)) + goto error; + + off = (off - t->size) % elem_type->size; + return btf_struct_access(log, elem_type, off, size, atype, next_btf_id); + +error: bpf_log(log, "access beyond struct %s at off %u size %u\n", tname, off, size); return -EACCES; -- 2.24.1