Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

btf: Support kernel parsing of BTF with layout info

Validate layout if present, but because the kernel must be
strict in what it accepts, reject BTF with unsupported kinds,
even if they are in the layout information.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260326145444.2076244-8-alan.maguire@oracle.com

authored by

Alan Maguire and committed by
Andrii Nakryiko
626e88c0 081677d0

+56 -4
+56 -4
kernel/bpf/btf.c
··· 270 270 struct btf_id_dtor_kfunc_tab *dtor_kfunc_tab; 271 271 struct btf_struct_metas *struct_meta_tab; 272 272 struct btf_struct_ops_tab *struct_ops_tab; 273 + struct btf_layout *layout; 273 274 274 275 /* split BTF support */ 275 276 struct btf *base_btf; ··· 1708 1707 __btf_verifier_log(log, "type_len: %u\n", hdr->type_len); 1709 1708 __btf_verifier_log(log, "str_off: %u\n", hdr->str_off); 1710 1709 __btf_verifier_log(log, "str_len: %u\n", hdr->str_len); 1710 + if (hdr->hdr_len >= sizeof(struct btf_header) && 1711 + btf_data_size >= hdr->hdr_len) { 1712 + __btf_verifier_log(log, "layout_off: %u\n", hdr->layout_off); 1713 + __btf_verifier_log(log, "layout_len: %u\n", hdr->layout_len); 1714 + } 1711 1715 __btf_verifier_log(log, "btf_total_size: %u\n", btf_data_size); 1712 1716 } 1713 1717 ··· 5532 5526 start = btf->nohdr_data + hdr->str_off; 5533 5527 end = start + hdr->str_len; 5534 5528 5535 - if (end != btf->data + btf->data_size) { 5529 + if (hdr->hdr_len < sizeof(struct btf_header) && 5530 + end != btf->data + btf->data_size) { 5536 5531 btf_verifier_log(env, "String section is not at the end"); 5537 5532 return -EINVAL; 5538 5533 } ··· 5554 5547 return 0; 5555 5548 } 5556 5549 5550 + static int btf_parse_layout_sec(struct btf_verifier_env *env) 5551 + { 5552 + const struct btf_header *hdr = &env->btf->hdr; 5553 + struct btf *btf = env->btf; 5554 + void *start, *end; 5555 + 5556 + if (hdr->hdr_len < sizeof(struct btf_header) || 5557 + hdr->layout_len == 0) 5558 + return 0; 5559 + 5560 + /* Layout section must align to 4 bytes */ 5561 + if (hdr->layout_off & (sizeof(u32) - 1)) { 5562 + btf_verifier_log(env, "Unaligned layout_off"); 5563 + return -EINVAL; 5564 + } 5565 + start = btf->nohdr_data + hdr->layout_off; 5566 + end = start + hdr->layout_len; 5567 + 5568 + if (hdr->layout_len < sizeof(struct btf_layout)) { 5569 + btf_verifier_log(env, "Layout section is too small"); 5570 + return -EINVAL; 5571 + } 5572 + if (hdr->layout_len % sizeof(struct btf_layout) != 0) { 5573 + btf_verifier_log(env, "layout_len is not multiple of %zu", 5574 + sizeof(struct btf_layout)); 5575 + return -EINVAL; 5576 + } 5577 + if (end > btf->data + btf->data_size) { 5578 + btf_verifier_log(env, "Layout section is too big"); 5579 + return -EINVAL; 5580 + } 5581 + btf->layout = start; 5582 + 5583 + return 0; 5584 + } 5585 + 5557 5586 static const size_t btf_sec_info_offset[] = { 5558 5587 offsetof(struct btf_header, type_off), 5559 5588 offsetof(struct btf_header, str_off), 5589 + offsetof(struct btf_header, layout_off) 5560 5590 }; 5561 5591 5562 5592 static int btf_sec_info_cmp(const void *a, const void *b) ··· 5609 5565 { 5610 5566 struct btf_sec_info secs[ARRAY_SIZE(btf_sec_info_offset)]; 5611 5567 u32 total, expected_total, i; 5568 + u32 nr_secs = ARRAY_SIZE(btf_sec_info_offset); 5612 5569 const struct btf_header *hdr; 5613 5570 const struct btf *btf; 5614 5571 5615 5572 btf = env->btf; 5616 5573 hdr = &btf->hdr; 5617 5574 5575 + if (hdr->hdr_len < sizeof(struct btf_header) || hdr->layout_len == 0) 5576 + nr_secs--; 5577 + 5618 5578 /* Populate the secs from hdr */ 5619 - for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++) 5579 + for (i = 0; i < nr_secs; i++) 5620 5580 secs[i] = *(struct btf_sec_info *)((void *)hdr + 5621 5581 btf_sec_info_offset[i]); 5622 5582 5623 - sort(secs, ARRAY_SIZE(btf_sec_info_offset), 5583 + sort(secs, nr_secs, 5624 5584 sizeof(struct btf_sec_info), btf_sec_info_cmp, NULL); 5625 5585 5626 5586 /* Check for gaps and overlap among sections */ 5627 5587 total = 0; 5628 5588 expected_total = btf_data_size - hdr->hdr_len; 5629 - for (i = 0; i < ARRAY_SIZE(btf_sec_info_offset); i++) { 5589 + for (i = 0; i < nr_secs; i++) { 5630 5590 if (expected_total < secs[i].off) { 5631 5591 btf_verifier_log(env, "Invalid section offset"); 5632 5592 return -EINVAL; ··· 5983 5935 btf->nohdr_data = btf->data + btf->hdr.hdr_len; 5984 5936 5985 5937 err = btf_parse_str_sec(env); 5938 + if (err) 5939 + goto errout; 5940 + 5941 + err = btf_parse_layout_sec(env); 5986 5942 if (err) 5987 5943 goto errout; 5988 5944