On Fri, Jun 16, 2023 at 10:18 AM Alan Maguire <alan.maguire@xxxxxxxxxx> wrote: > > Use kind layout to parse BTF with unknown kinds that have a > kind layout representation. > > Validate kind layout if present, and use it to parse BTF with > unrecognized kinds. Reject BTF that contains a type > of a kind that is not optional. > > Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx> > --- > kernel/bpf/btf.c | 102 +++++++++++++++++++++++++++++++++++++---------- > 1 file changed, 82 insertions(+), 20 deletions(-) > > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c > index bd2cac057928..ffe3926ea051 100644 > --- a/kernel/bpf/btf.c > +++ b/kernel/bpf/btf.c > @@ -257,6 +257,7 @@ struct btf { > struct btf_kfunc_set_tab *kfunc_set_tab; > struct btf_id_dtor_kfunc_tab *dtor_kfunc_tab; > struct btf_struct_metas *struct_meta_tab; > + struct btf_kind_layout *kind_layout; > > /* split BTF support */ > struct btf *base_btf; > @@ -4965,22 +4966,41 @@ static s32 btf_check_meta(struct btf_verifier_env *env, > return -EINVAL; > } > > - if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX || > - BTF_INFO_KIND(t->info) == BTF_KIND_UNKN) { > - btf_verifier_log(env, "[%u] Invalid kind:%u", > - env->log_type_id, BTF_INFO_KIND(t->info)); > - return -EINVAL; > - } > - > if (!btf_name_offset_valid(env->btf, t->name_off)) { > btf_verifier_log(env, "[%u] Invalid name_offset:%u", > env->log_type_id, t->name_off); > return -EINVAL; > } > > - var_meta_size = btf_type_ops(t)->check_meta(env, t, meta_left); > - if (var_meta_size < 0) > - return var_meta_size; > + if (BTF_INFO_KIND(t->info) == BTF_KIND_UNKN) { > + btf_verifier_log(env, "[%u] Invalid kind:%u", > + env->log_type_id, BTF_INFO_KIND(t->info)); > + return -EINVAL; > + } > + > + if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX && env->btf->kind_layout && > + (BTF_INFO_KIND(t->info) * sizeof(struct btf_kind_layout)) < > + env->btf->hdr.kind_layout_len) { > + struct btf_kind_layout *k = &env->btf->kind_layout[BTF_INFO_KIND(t->info)]; > + > + if (!(k->flags & BTF_KIND_LAYOUT_OPTIONAL)) { same question as on previous patch, should kernel trust and handle OPTIONAL flag? I'd say let's drop it for now, doesn't seem worth the trouble > + btf_verifier_log(env, "[%u] unknown but required kind %u", > + env->log_type_id, > + BTF_INFO_KIND(t->info)); > + return -EINVAL; > + } > + var_meta_size = sizeof(struct btf_type); > + var_meta_size += k->info_sz + (btf_type_vlen(t) * k->elem_sz); > + } else { > + if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX) { > + btf_verifier_log(env, "[%u] Invalid kind:%u", > + env->log_type_id, BTF_INFO_KIND(t->info)); > + return -EINVAL; > + } > + var_meta_size = btf_type_ops(t)->check_meta(env, t, meta_left); > + if (var_meta_size < 0) > + return var_meta_size; > + } > > meta_left -= var_meta_size; > > @@ -5155,7 +5175,8 @@ static int btf_parse_str_sec(struct btf_verifier_env *env) > start = btf->nohdr_data + hdr->str_off; > end = start + hdr->str_len; > > - if (end != btf->data + btf->data_size) { > + if (hdr->hdr_len < sizeof(struct btf_header) && > + end != btf->data + btf->data_size) { > btf_verifier_log(env, "String section is not at the end"); > return -EINVAL; > } > @@ -5176,9 +5197,41 @@ static int btf_parse_str_sec(struct btf_verifier_env *env) > return 0; > } > > +static int btf_parse_kind_layout_sec(struct btf_verifier_env *env) > +{ > + const struct btf_header *hdr = &env->btf->hdr; > + struct btf *btf = env->btf; > + void *start, *end; > + > + if (hdr->hdr_len < sizeof(struct btf_header) || > + hdr->kind_layout_len == 0) let's make sure that kind_layout_off is zero in this case as well > + return 0; > + > + /* Kind layout section must align to 4 bytes */ > + if (hdr->kind_layout_off & (sizeof(u32) - 1)) { > + btf_verifier_log(env, "Unaligned kind_layout_off"); > + return -EINVAL; > + } > + start = btf->nohdr_data + hdr->kind_layout_off; > + end = start + hdr->kind_layout_len; > + > + if (hdr->kind_layout_len < sizeof(struct btf_kind_layout)) { same as on libbpf side, more generally kind_layout_len should be a multiple of sizeof(struct btf_kind_layout) > + btf_verifier_log(env, "Kind layout section is too small"); > + return -EINVAL; > + } > + if (end != btf->data + btf->data_size) { > + btf_verifier_log(env, "Kind layout section is not at the end"); > + return -EINVAL; > + } > + btf->kind_layout = start; > + > + return 0; > +} > + [...]