[RFC PATCH bpf-next v2 11/17] bpf: support variable length array in tracing programs

Yonghong Song
2020-04-15T19:30:33Z

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@fb.com>
---
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