struct btf_id_dtor_kfunc_tab *dtor_kfunc_tab;
struct btf_struct_metas *struct_meta_tab;
struct btf_struct_ops_tab *struct_ops_tab;
+ struct btf_layout *layout;
/* split BTF support */
struct btf *base_btf;
__btf_verifier_log(log, "type_len: %u\n", hdr->type_len);
__btf_verifier_log(log, "str_off: %u\n", hdr->str_off);
__btf_verifier_log(log, "str_len: %u\n", hdr->str_len);
+ if (hdr->hdr_len >= sizeof(struct btf_header) &&
+ btf_data_size >= hdr->hdr_len) {
+ __btf_verifier_log(log, "layout_off: %u\n", hdr->layout_off);
+ __btf_verifier_log(log, "layout_len: %u\n", hdr->layout_len);
+ }
__btf_verifier_log(log, "btf_total_size: %u\n", btf_data_size);
}
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;
}
return 0;
}
+static int btf_parse_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->layout_len == 0)
+ return 0;
+
+ /* Layout section must align to 4 bytes */
+ if (hdr->layout_off & (sizeof(u32) - 1)) {
+ btf_verifier_log(env, "Unaligned layout_off");
+ return -EINVAL;
+ }
+ start = btf->nohdr_data + hdr->layout_off;
+ end = start + hdr->layout_len;
+
+ if (hdr->layout_len < sizeof(struct btf_layout)) {
+ btf_verifier_log(env, "Layout section is too small");
+ return -EINVAL;
+ }
+ if (hdr->layout_len % sizeof(struct btf_layout) != 0) {
+ btf_verifier_log(env, "layout_len is not multiple of %zu",
+ sizeof(struct btf_layout));
+ return -EINVAL;
+ }
+ if (end > btf->data + btf->data_size) {
+ btf_verifier_log(env, "Layout section is too big");
+ return -EINVAL;
+ }
+ btf->layout = start;
+
+ return 0;
+}
+
static const size_t btf_sec_info_offset[] = {
offsetof(struct btf_header, type_off),
offsetof(struct btf_header, str_off),
+ offsetof(struct btf_header, layout_off)
};
static int btf_sec_info_cmp(const void *a, const void *b)
{
struct btf_sec_info secs[ARRAY_SIZE(btf_sec_info_offset)];
u32 total, expected_total, i;
+ u32 nr_secs = ARRAY_SIZE(btf_sec_info_offset);
const struct btf_header *hdr;
const struct btf *btf;
btf = env->btf;
hdr = &btf->hdr;
+ if (hdr->hdr_len < sizeof(struct btf_header) || hdr->layout_len == 0)
+ nr_secs--;
+
/* Populate the secs from hdr */
- for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++)
+ for (i = 0; i < nr_secs; i++)
secs[i] = *(struct btf_sec_info *)((void *)hdr +
btf_sec_info_offset[i]);
- sort(secs, ARRAY_SIZE(btf_sec_info_offset),
+ sort(secs, nr_secs,
sizeof(struct btf_sec_info), btf_sec_info_cmp, NULL);
/* Check for gaps and overlap among sections */
total = 0;
expected_total = btf_data_size - hdr->hdr_len;
- for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++) {
+ for (i = 0; i < nr_secs; i++) {
if (expected_total < secs[i].off) {
btf_verifier_log(env, "Invalid section offset");
return -EINVAL;
if (err)
goto errout;
+ err = btf_parse_layout_sec(env);
+ if (err)
+ goto errout;
+
err = btf_parse_type_sec(env);
if (err)
goto errout;