bpf: Support variable length array in tracing programs
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> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Andrii Nakryiko <andriin@fb.com> Link: https://lore.kernel.org/bpf/20200509175916.2476853-1-yhs@fb.com
This commit is contained in:
Родитель
1d68f22b3d
Коммит
9c5f8a1008
|
@ -3833,6 +3833,7 @@ int btf_struct_access(struct bpf_verifier_log *log,
|
||||||
const struct btf_type *mtype, *elem_type = NULL;
|
const struct btf_type *mtype, *elem_type = NULL;
|
||||||
const struct btf_member *member;
|
const struct btf_member *member;
|
||||||
const char *tname, *mname;
|
const char *tname, *mname;
|
||||||
|
u32 vlen;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
tname = __btf_name_by_offset(btf_vmlinux, t->name_off);
|
tname = __btf_name_by_offset(btf_vmlinux, t->name_off);
|
||||||
|
@ -3841,7 +3842,43 @@ again:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vlen = btf_type_vlen(t);
|
||||||
if (off + size > t->size) {
|
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;
|
||||||
|
|
||||||
|
if (vlen == 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
member = btf_type_member(t) + vlen - 1;
|
||||||
|
mtype = btf_type_skip_modifiers(btf_vmlinux, member->type,
|
||||||
|
NULL);
|
||||||
|
if (!btf_type_is_array(mtype))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
array_elem = (struct btf_array *)(mtype + 1);
|
||||||
|
if (array_elem->nelems != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
moff = btf_member_bit_offset(t, member) / 8;
|
||||||
|
if (off < moff)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Only allow structure for now, can be relaxed for
|
||||||
|
* other types later.
|
||||||
|
*/
|
||||||
|
elem_type = btf_type_skip_modifiers(btf_vmlinux,
|
||||||
|
array_elem->type, NULL);
|
||||||
|
if (!btf_type_is_struct(elem_type))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
off = (off - moff) % 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",
|
bpf_log(log, "access beyond struct %s at off %u size %u\n",
|
||||||
tname, off, size);
|
tname, off, size);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче