Commit 9c5f8a10 authored by Yonghong Song's avatar Yonghong Song Committed by Alexei Starovoitov

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: default avatarYonghong Song <yhs@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarAndrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/20200509175916.2476853-1-yhs@fb.com
parent 1d68f22b
...@@ -3833,6 +3833,7 @@ int btf_struct_access(struct bpf_verifier_log *log, ...@@ -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 @@ int btf_struct_access(struct bpf_verifier_log *log, ...@@ -3841,7 +3842,43 @@ int btf_struct_access(struct bpf_verifier_log *log,
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment