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

bpf: Add in-kernel split BTF support

Adjust in-kernel BTF implementation to support a split BTF mode of operation.
Changes are mostly mirroring libbpf split BTF changes, with the exception of
start_id being 0 for in-kernel implementation due to simpler read-only mode.

Otherwise, for split BTF logic, most of the logic of jumping to base BTF,
where necessary, is encapsulated in few helper functions. Type numbering and
string offset in a split BTF are logically continuing where base BTF ends, so
most of the high-level logic is kept without changes.

Type verification and size resolution is only doing an added resolution of new
split BTF types and relies on already cached size and type resolution results
in the base BTF.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Song Liu <songliubraving@fb.com>
Link: https://lore.kernel.org/bpf/20201110011932.3201430-2-andrii@kernel.org

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
951bb646 f52b8fd3

+119 -52
+119 -52
kernel/bpf/btf.c
··· 203 203 const char *strings; 204 204 void *nohdr_data; 205 205 struct btf_header hdr; 206 - u32 nr_types; 206 + u32 nr_types; /* includes VOID for base BTF */ 207 207 u32 types_size; 208 208 u32 data_size; 209 209 refcount_t refcnt; 210 210 u32 id; 211 211 struct rcu_head rcu; 212 + 213 + /* split BTF support */ 214 + struct btf *base_btf; 215 + u32 start_id; /* first type ID in this BTF (0 for base BTF) */ 216 + u32 start_str_off; /* first string offset (0 for base BTF) */ 212 217 }; 213 218 214 219 enum verifier_phase { ··· 454 449 return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC; 455 450 } 456 451 452 + static u32 btf_nr_types_total(const struct btf *btf) 453 + { 454 + u32 total = 0; 455 + 456 + while (btf) { 457 + total += btf->nr_types; 458 + btf = btf->base_btf; 459 + } 460 + 461 + return total; 462 + } 463 + 457 464 s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind) 458 465 { 459 466 const struct btf_type *t; 460 467 const char *tname; 461 - u32 i; 468 + u32 i, total; 462 469 463 - for (i = 1; i <= btf->nr_types; i++) { 464 - t = btf->types[i]; 470 + total = btf_nr_types_total(btf); 471 + for (i = 1; i < total; i++) { 472 + t = btf_type_by_id(btf, i); 465 473 if (BTF_INFO_KIND(t->info) != kind) 466 474 continue; 467 475 ··· 617 599 618 600 static bool btf_name_offset_valid(const struct btf *btf, u32 offset) 619 601 { 620 - return BTF_STR_OFFSET_VALID(offset) && 621 - offset < btf->hdr.str_len; 602 + if (!BTF_STR_OFFSET_VALID(offset)) 603 + return false; 604 + 605 + while (offset < btf->start_str_off) 606 + btf = btf->base_btf; 607 + 608 + offset -= btf->start_str_off; 609 + return offset < btf->hdr.str_len; 622 610 } 623 611 624 612 static bool __btf_name_char_ok(char c, bool first, bool dot_ok) ··· 638 614 return true; 639 615 } 640 616 617 + static const char *btf_str_by_offset(const struct btf *btf, u32 offset) 618 + { 619 + while (offset < btf->start_str_off) 620 + btf = btf->base_btf; 621 + 622 + offset -= btf->start_str_off; 623 + if (offset < btf->hdr.str_len) 624 + return &btf->strings[offset]; 625 + 626 + return NULL; 627 + } 628 + 641 629 static bool __btf_name_valid(const struct btf *btf, u32 offset, bool dot_ok) 642 630 { 643 631 /* offset must be valid */ 644 - const char *src = &btf->strings[offset]; 632 + const char *src = btf_str_by_offset(btf, offset); 645 633 const char *src_limit; 646 634 647 635 if (!__btf_name_char_ok(*src, true, dot_ok)) ··· 686 650 687 651 static const char *__btf_name_by_offset(const struct btf *btf, u32 offset) 688 652 { 653 + const char *name; 654 + 689 655 if (!offset) 690 656 return "(anon)"; 691 - else if (offset < btf->hdr.str_len) 692 - return &btf->strings[offset]; 693 - else 694 - return "(invalid-name-offset)"; 657 + 658 + name = btf_str_by_offset(btf, offset); 659 + return name ?: "(invalid-name-offset)"; 695 660 } 696 661 697 662 const char *btf_name_by_offset(const struct btf *btf, u32 offset) 698 663 { 699 - if (offset < btf->hdr.str_len) 700 - return &btf->strings[offset]; 701 - 702 - return NULL; 664 + return btf_str_by_offset(btf, offset); 703 665 } 704 666 705 667 const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id) 706 668 { 707 - if (type_id > btf->nr_types) 708 - return NULL; 669 + while (type_id < btf->start_id) 670 + btf = btf->base_btf; 709 671 672 + type_id -= btf->start_id; 673 + if (type_id >= btf->nr_types) 674 + return NULL; 710 675 return btf->types[type_id]; 711 676 } 712 677 ··· 1427 1390 { 1428 1391 struct btf *btf = env->btf; 1429 1392 1430 - /* < 2 because +1 for btf_void which is always in btf->types[0]. 1431 - * btf_void is not accounted in btf->nr_types because btf_void 1432 - * does not come from the BTF file. 1433 - */ 1434 - if (btf->types_size - btf->nr_types < 2) { 1393 + if (btf->types_size == btf->nr_types) { 1435 1394 /* Expand 'types' array */ 1436 1395 1437 1396 struct btf_type **new_types; 1438 1397 u32 expand_by, new_size; 1439 1398 1440 - if (btf->types_size == BTF_MAX_TYPE) { 1399 + if (btf->start_id + btf->types_size == BTF_MAX_TYPE) { 1441 1400 btf_verifier_log(env, "Exceeded max num of types"); 1442 1401 return -E2BIG; 1443 1402 } ··· 1447 1414 if (!new_types) 1448 1415 return -ENOMEM; 1449 1416 1450 - if (btf->nr_types == 0) 1451 - new_types[0] = &btf_void; 1452 - else 1417 + if (btf->nr_types == 0) { 1418 + if (!btf->base_btf) { 1419 + /* lazily init VOID type */ 1420 + new_types[0] = &btf_void; 1421 + btf->nr_types++; 1422 + } 1423 + } else { 1453 1424 memcpy(new_types, btf->types, 1454 - sizeof(*btf->types) * (btf->nr_types + 1)); 1425 + sizeof(*btf->types) * btf->nr_types); 1426 + } 1455 1427 1456 1428 kvfree(btf->types); 1457 1429 btf->types = new_types; 1458 1430 btf->types_size = new_size; 1459 1431 } 1460 1432 1461 - btf->types[++(btf->nr_types)] = t; 1433 + btf->types[btf->nr_types++] = t; 1462 1434 1463 1435 return 0; 1464 1436 } ··· 1536 1498 u32 *resolved_ids = NULL; 1537 1499 u8 *visit_states = NULL; 1538 1500 1539 - /* +1 for btf_void */ 1540 - resolved_sizes = kvcalloc(nr_types + 1, sizeof(*resolved_sizes), 1501 + resolved_sizes = kvcalloc(nr_types, sizeof(*resolved_sizes), 1541 1502 GFP_KERNEL | __GFP_NOWARN); 1542 1503 if (!resolved_sizes) 1543 1504 goto nomem; 1544 1505 1545 - resolved_ids = kvcalloc(nr_types + 1, sizeof(*resolved_ids), 1506 + resolved_ids = kvcalloc(nr_types, sizeof(*resolved_ids), 1546 1507 GFP_KERNEL | __GFP_NOWARN); 1547 1508 if (!resolved_ids) 1548 1509 goto nomem; 1549 1510 1550 - visit_states = kvcalloc(nr_types + 1, sizeof(*visit_states), 1511 + visit_states = kvcalloc(nr_types, sizeof(*visit_states), 1551 1512 GFP_KERNEL | __GFP_NOWARN); 1552 1513 if (!visit_states) 1553 1514 goto nomem; ··· 1598 1561 static bool env_type_is_resolved(const struct btf_verifier_env *env, 1599 1562 u32 type_id) 1600 1563 { 1601 - return env->visit_states[type_id] == RESOLVED; 1564 + /* base BTF types should be resolved by now */ 1565 + if (type_id < env->btf->start_id) 1566 + return true; 1567 + 1568 + return env->visit_states[type_id - env->btf->start_id] == RESOLVED; 1602 1569 } 1603 1570 1604 1571 static int env_stack_push(struct btf_verifier_env *env, 1605 1572 const struct btf_type *t, u32 type_id) 1606 1573 { 1574 + const struct btf *btf = env->btf; 1607 1575 struct resolve_vertex *v; 1608 1576 1609 1577 if (env->top_stack == MAX_RESOLVE_DEPTH) 1610 1578 return -E2BIG; 1611 1579 1612 - if (env->visit_states[type_id] != NOT_VISITED) 1580 + if (type_id < btf->start_id 1581 + || env->visit_states[type_id - btf->start_id] != NOT_VISITED) 1613 1582 return -EEXIST; 1614 1583 1615 - env->visit_states[type_id] = VISITED; 1584 + env->visit_states[type_id - btf->start_id] = VISITED; 1616 1585 1617 1586 v = &env->stack[env->top_stack++]; 1618 1587 v->t = t; ··· 1648 1605 u32 type_id = env->stack[--(env->top_stack)].type_id; 1649 1606 struct btf *btf = env->btf; 1650 1607 1608 + type_id -= btf->start_id; /* adjust to local type id */ 1651 1609 btf->resolved_sizes[type_id] = resolved_size; 1652 1610 btf->resolved_ids[type_id] = resolved_type_id; 1653 1611 env->visit_states[type_id] = RESOLVED; ··· 1753 1709 return __btf_resolve_size(btf, type, type_size, NULL, NULL, NULL, NULL); 1754 1710 } 1755 1711 1712 + static u32 btf_resolved_type_id(const struct btf *btf, u32 type_id) 1713 + { 1714 + while (type_id < btf->start_id) 1715 + btf = btf->base_btf; 1716 + 1717 + return btf->resolved_ids[type_id - btf->start_id]; 1718 + } 1719 + 1756 1720 /* The input param "type_id" must point to a needs_resolve type */ 1757 1721 static const struct btf_type *btf_type_id_resolve(const struct btf *btf, 1758 1722 u32 *type_id) 1759 1723 { 1760 - *type_id = btf->resolved_ids[*type_id]; 1724 + *type_id = btf_resolved_type_id(btf, *type_id); 1761 1725 return btf_type_by_id(btf, *type_id); 1726 + } 1727 + 1728 + static u32 btf_resolved_type_size(const struct btf *btf, u32 type_id) 1729 + { 1730 + while (type_id < btf->start_id) 1731 + btf = btf->base_btf; 1732 + 1733 + return btf->resolved_sizes[type_id - btf->start_id]; 1762 1734 } 1763 1735 1764 1736 const struct btf_type *btf_type_id_size(const struct btf *btf, ··· 1791 1731 if (btf_type_has_size(size_type)) { 1792 1732 size = size_type->size; 1793 1733 } else if (btf_type_is_array(size_type)) { 1794 - size = btf->resolved_sizes[size_type_id]; 1734 + size = btf_resolved_type_size(btf, size_type_id); 1795 1735 } else if (btf_type_is_ptr(size_type)) { 1796 1736 size = sizeof(void *); 1797 1737 } else { ··· 1799 1739 !btf_type_is_var(size_type))) 1800 1740 return NULL; 1801 1741 1802 - size_type_id = btf->resolved_ids[size_type_id]; 1742 + size_type_id = btf_resolved_type_id(btf, size_type_id); 1803 1743 size_type = btf_type_by_id(btf, size_type_id); 1804 1744 if (btf_type_nosize_or_null(size_type)) 1805 1745 return NULL; 1806 1746 else if (btf_type_has_size(size_type)) 1807 1747 size = size_type->size; 1808 1748 else if (btf_type_is_array(size_type)) 1809 - size = btf->resolved_sizes[size_type_id]; 1749 + size = btf_resolved_type_size(btf, size_type_id); 1810 1750 else if (btf_type_is_ptr(size_type)) 1811 1751 size = sizeof(void *); 1812 1752 else ··· 3858 3798 cur = btf->nohdr_data + hdr->type_off; 3859 3799 end = cur + hdr->type_len; 3860 3800 3861 - env->log_type_id = 1; 3801 + env->log_type_id = btf->base_btf ? btf->start_id : 1; 3862 3802 while (cur < end) { 3863 3803 struct btf_type *t = cur; 3864 3804 s32 meta_size; ··· 3885 3825 return false; 3886 3826 3887 3827 if (btf_type_is_struct(t) || btf_type_is_datasec(t)) 3888 - return !btf->resolved_ids[type_id] && 3889 - !btf->resolved_sizes[type_id]; 3828 + return !btf_resolved_type_id(btf, type_id) && 3829 + !btf_resolved_type_size(btf, type_id); 3890 3830 3891 3831 if (btf_type_is_modifier(t) || btf_type_is_ptr(t) || 3892 3832 btf_type_is_var(t)) { ··· 3906 3846 elem_type = btf_type_id_size(btf, &elem_type_id, &elem_size); 3907 3847 return elem_type && !btf_type_is_modifier(elem_type) && 3908 3848 (array->nelems * elem_size == 3909 - btf->resolved_sizes[type_id]); 3849 + btf_resolved_type_size(btf, type_id)); 3910 3850 } 3911 3851 3912 3852 return false; ··· 3948 3888 static int btf_check_all_types(struct btf_verifier_env *env) 3949 3889 { 3950 3890 struct btf *btf = env->btf; 3951 - u32 type_id; 3891 + const struct btf_type *t; 3892 + u32 type_id, i; 3952 3893 int err; 3953 3894 3954 3895 err = env_resolve_init(env); ··· 3957 3896 return err; 3958 3897 3959 3898 env->phase++; 3960 - for (type_id = 1; type_id <= btf->nr_types; type_id++) { 3961 - const struct btf_type *t = btf_type_by_id(btf, type_id); 3899 + for (i = btf->base_btf ? 0 : 1; i < btf->nr_types; i++) { 3900 + type_id = btf->start_id + i; 3901 + t = btf_type_by_id(btf, type_id); 3962 3902 3963 3903 env->log_type_id = type_id; 3964 3904 if (btf_type_needs_resolve(t) && ··· 3996 3934 return -EINVAL; 3997 3935 } 3998 3936 3999 - if (!hdr->type_len) { 3937 + if (!env->btf->base_btf && !hdr->type_len) { 4000 3938 btf_verifier_log(env, "No type found"); 4001 3939 return -EINVAL; 4002 3940 } ··· 4023 3961 return -EINVAL; 4024 3962 } 4025 3963 4026 - if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_NAME_OFFSET || 4027 - start[0] || end[-1]) { 3964 + btf->strings = start; 3965 + 3966 + if (btf->base_btf && !hdr->str_len) 3967 + return 0; 3968 + if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_NAME_OFFSET || end[-1]) { 4028 3969 btf_verifier_log(env, "Invalid string section"); 4029 3970 return -EINVAL; 4030 3971 } 4031 - 4032 - btf->strings = start; 3972 + if (!btf->base_btf && start[0]) { 3973 + btf_verifier_log(env, "Invalid string section"); 3974 + return -EINVAL; 3975 + } 4033 3976 4034 3977 return 0; 4035 3978 } ··· 4975 4908 while (t && btf_type_is_modifier(t)) 4976 4909 t = btf_type_by_id(btf, t->type); 4977 4910 if (!t) { 4978 - *bad_type = btf->types[0]; 4911 + *bad_type = btf_type_by_id(btf, 0); 4979 4912 return -EINVAL; 4980 4913 } 4981 4914 if (btf_type_is_ptr(t))