diff mbox series

[v4,bpf-next,13/17] bpf: support standalone BTF in modules

Message ID 20231112124834.388735-14-alan.maguire@oracle.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series Add kind layout, CRCs to BTF | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-16 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-16 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-16 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-16 / veristat
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 fail Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-5 fail Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 fail Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-15 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-16 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 fail Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 fail Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 fail Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 fail Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-llvm-16 / build / build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 fail Logs for x86_64-llvm-16 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-26 fail Logs for x86_64-llvm-16 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-27 fail Logs for x86_64-llvm-16 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-16 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-16 / veristat
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 fail Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-11 fail Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-10 fail Logs for s390x-gcc / test (test_maps, false, 360) / test_maps on s390x with gcc
netdev/series_format fail Series longer than 15 patches (and no cover letter)
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 1140 this patch: 18
netdev/cc_maintainers success CCed 12 of 12 maintainers
netdev/build_clang fail Errors and warnings before: 1162 this patch: 19
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 1167 this patch: 18
netdev/checkpatch warning WARNING: line length of 102 exceeds 80 columns WARNING: line length of 82 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 86 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Alan Maguire Nov. 12, 2023, 12:48 p.m. UTC
Not all kernel modules can be built in-tree when the core
kernel is built. This presents a problem for split BTF, because
split module BTF refers to type ids in the base kernel BTF, and
if that base kernel BTF changes (even in minor ways) those
references become invalid.  Such modules then cannot take
advantage of BTF (or at least they only can until the kernel
changes enough to invalidate their vmlinux type id references).
This problem has been discussed before, and the initial approach
was to allow BTF mismatch but fail to load BTF.  See [1]
for more discussion.

Generating standalone BTF for modules helps solve this problem
because the BTF generated is self-referential only.  However,
tooling is geared towards split BTF - for example bpftool assumes
a module's BTF is defined relative to vmlinux BTF.  To handle
this, dynamic remapping of standalone BTF is done on module
load to make it appear like split BTF - type ids and string
offsets are remapped such that they appear as they would in
split BTF.  It just so happens that the BTF is self-referential.
With this approach, existing tooling works with standalone
module BTF from /sys/kernel/btf in the same way as before;
no knowledge of split versus standalone BTF is required.

To verify that the module BTF is standalone we verify that
either

1. a CRC is present for BTF, but no base CRC is specified;
   this indicates that BTF was not generated relative to
   base BTF; or

2. the string offsets all lie within the range
   <0, string_section_size>; and
3. the BTF ids all lie within range
   <0, number_of_types_in_module_BTF>

Case 1 is a fastpath available when pahole generates CRCs.
The tests carried out in 2 and 3 are fallbacks for when newer
pahole is not present.

If these conditions are true, BTF and string ids are remapped
such that they appear to be split BTF.

Note that the kfunc and dtor ids need to be remapped also
on registration, since they will be out-of-date with respect
to the remapped module BTF.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>

[1] https://lore.kernel.org/bpf/YfK18x%2FXrYL4Vw8o@syu-laptop/
---
 kernel/bpf/btf.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 302 insertions(+), 2 deletions(-)

Comments

kernel test robot Nov. 12, 2023, 3:35 p.m. UTC | #1
Hi Alan,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Alan-Maguire/btf-add-kind-layout-encoding-crcs-to-UAPI/20231112-205314
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20231112124834.388735-14-alan.maguire%40oracle.com
patch subject: [PATCH v4 bpf-next 13/17] bpf: support standalone BTF in modules
config: nios2-allmodconfig (https://download.01.org/0day-ci/archive/20231112/202311122307.bjlq3XJ5-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231112/202311122307.bjlq3XJ5-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311122307.bjlq3XJ5-lkp@intel.com/

All errors (new ones prefixed by >>):

   kernel/bpf/btf.c: In function 'btf_seq_show':
   kernel/bpf/btf.c:7447:29: warning: function 'btf_seq_show' might be a candidate for 'gnu_printf' format attribute [-Wsuggest-attribute=format]
    7447 |         seq_vprintf((struct seq_file *)show->target, fmt, args);
         |                             ^~~~~~~~
   kernel/bpf/btf.c: In function 'btf_snprintf_show':
   kernel/bpf/btf.c:7484:9: warning: function 'btf_snprintf_show' might be a candidate for 'gnu_printf' format attribute [-Wsuggest-attribute=format]
    7484 |         len = vsnprintf(show->target, ssnprintf->len_left, fmt, args);
         |         ^~~
   kernel/bpf/btf.c: In function 'btf_populate_kfunc_set':
>> kernel/bpf/btf.c:8153:44: error: implicit declaration of function 'btf_id_renumber'; did you mean 'btf_is_enum64'? [-Werror=implicit-function-declaration]
    8153 |                         set->pairs[i].id = btf_id_renumber(btf, set->pairs[i].id);
         |                                            ^~~~~~~~~~~~~~~
         |                                            btf_is_enum64
   cc1: some warnings being treated as errors


vim +8153 kernel/bpf/btf.c

  8046	
  8047	static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook,
  8048					  const struct btf_kfunc_id_set *kset)
  8049	{
  8050		struct btf_kfunc_hook_filter *hook_filter;
  8051		struct btf_id_set8 *add_set = kset->set;
  8052		bool vmlinux_set = !btf_is_module(btf);
  8053		bool add_filter = !!kset->filter;
  8054		struct btf_kfunc_set_tab *tab;
  8055		struct btf_id_set8 *set;
  8056		u32 set_cnt;
  8057		int ret;
  8058	
  8059		if (hook >= BTF_KFUNC_HOOK_MAX) {
  8060			ret = -EINVAL;
  8061			goto end;
  8062		}
  8063	
  8064		if (!add_set->cnt)
  8065			return 0;
  8066	
  8067		tab = btf->kfunc_set_tab;
  8068	
  8069		if (tab && add_filter) {
  8070			u32 i;
  8071	
  8072			hook_filter = &tab->hook_filters[hook];
  8073			for (i = 0; i < hook_filter->nr_filters; i++) {
  8074				if (hook_filter->filters[i] == kset->filter) {
  8075					add_filter = false;
  8076					break;
  8077				}
  8078			}
  8079	
  8080			if (add_filter && hook_filter->nr_filters == BTF_KFUNC_FILTER_MAX_CNT) {
  8081				ret = -E2BIG;
  8082				goto end;
  8083			}
  8084		}
  8085	
  8086		if (!tab) {
  8087			tab = kzalloc(sizeof(*tab), GFP_KERNEL | __GFP_NOWARN);
  8088			if (!tab)
  8089				return -ENOMEM;
  8090			btf->kfunc_set_tab = tab;
  8091		}
  8092	
  8093		set = tab->sets[hook];
  8094		/* Warn when register_btf_kfunc_id_set is called twice for the same hook
  8095		 * for module sets.
  8096		 */
  8097		if (WARN_ON_ONCE(set && !vmlinux_set)) {
  8098			ret = -EINVAL;
  8099			goto end;
  8100		}
  8101	
  8102		/* We don't need to allocate, concatenate, and sort module sets, because
  8103		 * only one is allowed per hook. Hence, we can directly assign the
  8104		 * pointer and return.
  8105		 */
  8106		if (!vmlinux_set) {
  8107			tab->sets[hook] = add_set;
  8108			goto do_add_filter;
  8109		}
  8110	
  8111		/* In case of vmlinux sets, there may be more than one set being
  8112		 * registered per hook. To create a unified set, we allocate a new set
  8113		 * and concatenate all individual sets being registered. While each set
  8114		 * is individually sorted, they may become unsorted when concatenated,
  8115		 * hence re-sorting the final set again is required to make binary
  8116		 * searching the set using btf_id_set8_contains function work.
  8117		 */
  8118		set_cnt = set ? set->cnt : 0;
  8119	
  8120		if (set_cnt > U32_MAX - add_set->cnt) {
  8121			ret = -EOVERFLOW;
  8122			goto end;
  8123		}
  8124	
  8125		if (set_cnt + add_set->cnt > BTF_KFUNC_SET_MAX_CNT) {
  8126			ret = -E2BIG;
  8127			goto end;
  8128		}
  8129	
  8130		/* Grow set */
  8131		set = krealloc(tab->sets[hook],
  8132			       offsetof(struct btf_id_set8, pairs[set_cnt + add_set->cnt]),
  8133			       GFP_KERNEL | __GFP_NOWARN);
  8134		if (!set) {
  8135			ret = -ENOMEM;
  8136			goto end;
  8137		}
  8138	
  8139		/* For newly allocated set, initialize set->cnt to 0 */
  8140		if (!tab->sets[hook])
  8141			set->cnt = 0;
  8142		tab->sets[hook] = set;
  8143	
  8144		/* Concatenate the two sets */
  8145		memcpy(set->pairs + set->cnt, add_set->pairs, add_set->cnt * sizeof(set->pairs[0]));
  8146		if (btf->standalone_btf) {
  8147			u32 i;
  8148	
  8149			/* renumber BTF ids since BTF is standalone and has been mapped to look
  8150			 * like split BTF, while BTF kfunc ids are still old unmapped values.
  8151			 */
  8152			for (i = set->cnt; i < set->cnt + add_set->cnt; i++)
> 8153				set->pairs[i].id = btf_id_renumber(btf, set->pairs[i].id);
  8154		}
  8155	
  8156		set->cnt += add_set->cnt;
  8157	
  8158		sort(set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func, NULL);
  8159	
  8160	do_add_filter:
  8161		if (add_filter) {
  8162			hook_filter = &tab->hook_filters[hook];
  8163			hook_filter->filters[hook_filter->nr_filters++] = kset->filter;
  8164		}
  8165		return 0;
  8166	end:
  8167		btf_free_kfunc_set_tab(btf);
  8168		return ret;
  8169	}
  8170
kernel test robot Nov. 12, 2023, 8 p.m. UTC | #2
Hi Alan,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Alan-Maguire/btf-add-kind-layout-encoding-crcs-to-UAPI/20231112-205314
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20231112124834.388735-14-alan.maguire%40oracle.com
patch subject: [PATCH v4 bpf-next 13/17] bpf: support standalone BTF in modules
config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20231113/202311130324.ONOHc3XN-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231113/202311130324.ONOHc3XN-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311130324.ONOHc3XN-lkp@intel.com/

All errors (new ones prefixed by >>):

>> kernel/bpf/btf.c:8153:23: error: call to undeclared function 'btf_id_renumber'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
                           set->pairs[i].id = btf_id_renumber(btf, set->pairs[i].id);
                                              ^
   kernel/bpf/btf.c:8290:15: error: call to undeclared function 'btf_id_renumber'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
                           kfunc_id = btf_id_renumber(btf, kfunc_id);
                                      ^
   kernel/bpf/btf.c:8353:18: error: call to undeclared function 'btf_id_renumber'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
                           dtor_btf_id = btf_id_renumber(btf, dtor_btf_id);
                                         ^
   kernel/bpf/btf.c:8455:27: error: call to undeclared function 'btf_id_renumber'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
                           tab->dtors[i].btf_id = btf_id_renumber(btf, tab->dtors[i].btf_id);
                                                  ^
   4 errors generated.


vim +/btf_id_renumber +8153 kernel/bpf/btf.c

  8046	
  8047	static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook,
  8048					  const struct btf_kfunc_id_set *kset)
  8049	{
  8050		struct btf_kfunc_hook_filter *hook_filter;
  8051		struct btf_id_set8 *add_set = kset->set;
  8052		bool vmlinux_set = !btf_is_module(btf);
  8053		bool add_filter = !!kset->filter;
  8054		struct btf_kfunc_set_tab *tab;
  8055		struct btf_id_set8 *set;
  8056		u32 set_cnt;
  8057		int ret;
  8058	
  8059		if (hook >= BTF_KFUNC_HOOK_MAX) {
  8060			ret = -EINVAL;
  8061			goto end;
  8062		}
  8063	
  8064		if (!add_set->cnt)
  8065			return 0;
  8066	
  8067		tab = btf->kfunc_set_tab;
  8068	
  8069		if (tab && add_filter) {
  8070			u32 i;
  8071	
  8072			hook_filter = &tab->hook_filters[hook];
  8073			for (i = 0; i < hook_filter->nr_filters; i++) {
  8074				if (hook_filter->filters[i] == kset->filter) {
  8075					add_filter = false;
  8076					break;
  8077				}
  8078			}
  8079	
  8080			if (add_filter && hook_filter->nr_filters == BTF_KFUNC_FILTER_MAX_CNT) {
  8081				ret = -E2BIG;
  8082				goto end;
  8083			}
  8084		}
  8085	
  8086		if (!tab) {
  8087			tab = kzalloc(sizeof(*tab), GFP_KERNEL | __GFP_NOWARN);
  8088			if (!tab)
  8089				return -ENOMEM;
  8090			btf->kfunc_set_tab = tab;
  8091		}
  8092	
  8093		set = tab->sets[hook];
  8094		/* Warn when register_btf_kfunc_id_set is called twice for the same hook
  8095		 * for module sets.
  8096		 */
  8097		if (WARN_ON_ONCE(set && !vmlinux_set)) {
  8098			ret = -EINVAL;
  8099			goto end;
  8100		}
  8101	
  8102		/* We don't need to allocate, concatenate, and sort module sets, because
  8103		 * only one is allowed per hook. Hence, we can directly assign the
  8104		 * pointer and return.
  8105		 */
  8106		if (!vmlinux_set) {
  8107			tab->sets[hook] = add_set;
  8108			goto do_add_filter;
  8109		}
  8110	
  8111		/* In case of vmlinux sets, there may be more than one set being
  8112		 * registered per hook. To create a unified set, we allocate a new set
  8113		 * and concatenate all individual sets being registered. While each set
  8114		 * is individually sorted, they may become unsorted when concatenated,
  8115		 * hence re-sorting the final set again is required to make binary
  8116		 * searching the set using btf_id_set8_contains function work.
  8117		 */
  8118		set_cnt = set ? set->cnt : 0;
  8119	
  8120		if (set_cnt > U32_MAX - add_set->cnt) {
  8121			ret = -EOVERFLOW;
  8122			goto end;
  8123		}
  8124	
  8125		if (set_cnt + add_set->cnt > BTF_KFUNC_SET_MAX_CNT) {
  8126			ret = -E2BIG;
  8127			goto end;
  8128		}
  8129	
  8130		/* Grow set */
  8131		set = krealloc(tab->sets[hook],
  8132			       offsetof(struct btf_id_set8, pairs[set_cnt + add_set->cnt]),
  8133			       GFP_KERNEL | __GFP_NOWARN);
  8134		if (!set) {
  8135			ret = -ENOMEM;
  8136			goto end;
  8137		}
  8138	
  8139		/* For newly allocated set, initialize set->cnt to 0 */
  8140		if (!tab->sets[hook])
  8141			set->cnt = 0;
  8142		tab->sets[hook] = set;
  8143	
  8144		/* Concatenate the two sets */
  8145		memcpy(set->pairs + set->cnt, add_set->pairs, add_set->cnt * sizeof(set->pairs[0]));
  8146		if (btf->standalone_btf) {
  8147			u32 i;
  8148	
  8149			/* renumber BTF ids since BTF is standalone and has been mapped to look
  8150			 * like split BTF, while BTF kfunc ids are still old unmapped values.
  8151			 */
  8152			for (i = set->cnt; i < set->cnt + add_set->cnt; i++)
> 8153				set->pairs[i].id = btf_id_renumber(btf, set->pairs[i].id);
  8154		}
  8155	
  8156		set->cnt += add_set->cnt;
  8157	
  8158		sort(set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func, NULL);
  8159	
  8160	do_add_filter:
  8161		if (add_filter) {
  8162			hook_filter = &tab->hook_filters[hook];
  8163			hook_filter->filters[hook_filter->nr_filters++] = kset->filter;
  8164		}
  8165		return 0;
  8166	end:
  8167		btf_free_kfunc_set_tab(btf);
  8168		return ret;
  8169	}
  8170
diff mbox series

Patch

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index a51dc3ef6a56..412184ade0f1 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -267,6 +267,7 @@  struct btf {
 	u32 start_str_off; /* first string offset (0 for base BTF) */
 	char name[MODULE_NAME_LEN];
 	bool kernel_btf;
+	bool standalone_btf;
 };
 
 enum verifier_phase {
@@ -5882,6 +5883,253 @@  struct btf *btf_parse_vmlinux(void)
 
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 
+/* verify module BTF is self-contained:
+ * - if CRC is set and base CRC is not: or
+ *  - no string offset should exceed standalone str len; and
+ *  - the max id referenced should be <= the number of btf types in module BTF
+ *
+ * Taken together with the fact that the number of module types is much less
+ * than the number of types in vmliux BTF, these imply self-reference and hence
+ * standalone BTF.
+ */
+static bool btf_module_is_standalone(struct btf_verifier_env *env)
+{
+	u32 id_max = 0, num_ids = 0;
+	struct btf *btf = env->btf;
+	struct btf_header *hdr;
+	void *cur, *end;
+	u32 end_str_off;
+
+	hdr = &btf->hdr;
+	cur = btf->nohdr_data + hdr->type_off;
+	end = cur + hdr->type_len;
+	end_str_off = hdr->str_len;
+
+	/* Quick CRC test; if base CRC is absent while CRC is present,
+	 * we know BTF was generated without reference to base BTF.
+	 */
+	if (hdr->hdr_len >= sizeof(struct btf_header)) {
+		if ((hdr->flags & BTF_FLAG_CRC_SET) &&
+		    !(hdr->flags & BTF_FLAG_BASE_CRC_SET))
+			return true;
+	}
+
+	while (cur < end) {
+		struct btf_type *t = cur;
+		u32 meta_size = sizeof(*t);
+		struct btf_member *member;
+		struct btf_param *param;
+		struct btf_array *array;
+		struct btf_enum64 *e64;
+		struct btf_enum *e;
+		int i, vlen;
+
+		if (t->name_off >= end_str_off)
+			return false;
+
+		switch (btf_kind(t)) {
+		case BTF_KIND_FLOAT:
+			break;
+		case BTF_KIND_PTR:
+		case BTF_KIND_FWD:
+		case BTF_KIND_TYPEDEF:
+		case BTF_KIND_VOLATILE:
+		case BTF_KIND_CONST:
+		case BTF_KIND_RESTRICT:
+		case BTF_KIND_FUNC:
+		case BTF_KIND_TYPE_TAG:
+			if (t->type > id_max)
+				id_max = t->type;
+			break;
+		case BTF_KIND_VAR:
+			if (t->type > id_max)
+				id_max = t->type;
+			meta_size += sizeof(struct btf_var);
+			break;
+		case BTF_KIND_INT:
+			meta_size += sizeof(u32);
+			break;
+		case BTF_KIND_DATASEC:
+			meta_size += btf_vlen(t) * sizeof(struct btf_var_secinfo);
+			break;
+		case BTF_KIND_ARRAY:
+			array = (struct btf_array *)(t + 1);
+			if (array->type > id_max)
+				id_max = array->type;
+			if (array->index_type > id_max)
+				id_max = array->index_type;
+			meta_size += sizeof(*array);
+			break;
+		case BTF_KIND_STRUCT:
+		case BTF_KIND_UNION:
+			member = (struct btf_member *)(t + 1);
+			vlen = btf_type_vlen(t);
+			for (i = 0; i < vlen; i++, member++) {
+				if (member->name_off >= end_str_off)
+					return false;
+				if (member->type > id_max)
+					id_max = member->type;
+			}
+			meta_size += vlen * sizeof(*member);
+			break;
+		case BTF_KIND_ENUM:
+			e = (struct btf_enum *)(t + 1);
+			vlen = btf_type_vlen(t);
+			for (i = 0; i < vlen; i++, e++) {
+				if  (e->name_off > end_str_off)
+					return false;
+			}
+			meta_size +=  vlen * sizeof(*e);
+			break;
+		case BTF_KIND_ENUM64:
+			e64 = (struct btf_enum64 *)(t + 1);
+			vlen = btf_type_vlen(t);
+			for (i = 0; i < vlen; i++, e64++) {
+				if (e64->name_off > end_str_off)
+					return false;
+			}
+			meta_size += vlen * sizeof(*e64);
+			break;
+		case BTF_KIND_FUNC_PROTO:
+			param = (struct btf_param *)(t + 1);
+			vlen = btf_type_vlen(t);
+			for (i = 0; i < vlen; i++, param++) {
+				if (param->name_off > end_str_off)
+					return false;
+				if (param->type > id_max)
+					id_max = param->type;
+			}
+			meta_size += vlen * sizeof(*param);
+			break;
+		case BTF_KIND_DECL_TAG:
+			if (t->type > id_max)
+				id_max = t->type;
+			meta_size += sizeof(struct btf_decl_tag);
+			break;
+		}
+		cur += meta_size;
+		num_ids++;
+	}
+	/* if all standalone string checks look good and we found no references
+	 * to ids higher than the number present here, we can be sure it is
+	 * standalone BTF.
+	 */
+	return id_max <= num_ids;
+}
+
+static u32 btf_name_off_renumber(struct btf *btf, u32 name_off)
+{
+	/* no need to renumber empty string */
+	if (name_off == 0)
+		return name_off;
+	return name_off + btf->start_str_off;
+}
+
+static u32 btf_id_renumber(struct btf *btf, u32 id)
+{
+	/* no need to renumber void type id */
+	if (id == 0)
+		return id;
+
+	return id + btf->start_id - 1;
+}
+
+/* Renumber standalone BTF to appear as split BTF; name offsets must
+ * be relative to btf->start_str_offset and ids relative to btf->start_id.
+ * When user sees BTF it will appear as normal module split BTF, the only
+ * difference being it is fully self-referential and does not refer back
+ * to vmlinux BTF (aside from 0 "void" references).
+ */
+static void btf_type_renumber(struct btf_verifier_env *env, struct btf_type *t)
+{
+	struct btf_var_secinfo *secinfo;
+	struct btf *btf = env->btf;
+	struct btf_member *member;
+	struct btf_param *param;
+	struct btf_array *array;
+	struct btf_enum64 *e64;
+	struct btf_enum *e;
+	int i, vlen;
+
+	t->name_off = btf_name_off_renumber(btf, t->name_off);
+
+	switch (BTF_INFO_KIND(t->info)) {
+	case BTF_KIND_INT:
+	case BTF_KIND_FLOAT:
+		/* nothing to renumber here, no type references */
+		break;
+	case BTF_KIND_PTR:
+	case BTF_KIND_FWD:
+	case BTF_KIND_TYPEDEF:
+	case BTF_KIND_VOLATILE:
+	case BTF_KIND_CONST:
+	case BTF_KIND_RESTRICT:
+	case BTF_KIND_FUNC:
+	case BTF_KIND_VAR:
+	case BTF_KIND_TYPE_TAG:
+	case BTF_KIND_DECL_TAG:
+		/* renumber the referenced type */
+		t->type = btf_id_renumber(btf, t->type);
+		break;
+	case BTF_KIND_ARRAY:
+		array = btf_array(t);
+		array->type = btf_id_renumber(btf, array->type);
+		array->index_type = btf_id_renumber(btf, array->index_type);
+		break;
+	case BTF_KIND_STRUCT:
+	case BTF_KIND_UNION:
+		member = (struct btf_member *)(t + 1);
+		vlen = btf_type_vlen(t);
+		for (i = 0; i < vlen; i++, member++) {
+			member->type = btf_id_renumber(btf, member->type);
+			member->name_off = btf_name_off_renumber(btf, member->name_off);
+		}
+		break;
+	case BTF_KIND_FUNC_PROTO:
+		param = (struct btf_param *)(t + 1);
+		vlen = btf_type_vlen(t);
+		for (i = 0; i < vlen; i++, param++) {
+			param->type = btf_id_renumber(btf, param->type);
+			param->name_off = btf_name_off_renumber(btf, param->name_off);
+		}
+		break;
+	case BTF_KIND_DATASEC:
+		vlen = btf_type_vlen(t);
+		secinfo = (struct btf_var_secinfo *)(t + 1);
+		for (i = 0; i < vlen; i++, secinfo++)
+			secinfo->type = btf_id_renumber(btf, secinfo->type);
+		break;
+	case BTF_KIND_ENUM:
+		e = (struct btf_enum *)(t + 1);
+		vlen = btf_type_vlen(t);
+		for (i = 0; i < vlen; i++, e++)
+			e->name_off = btf_name_off_renumber(btf, e->name_off);
+		break;
+	case BTF_KIND_ENUM64:
+		e64 = (struct btf_enum64 *)(t + 1);
+		vlen = btf_type_vlen(t);
+		for (i = 0; i < vlen; i++, e64++)
+			e64->name_off = btf_name_off_renumber(btf, e64->name_off);
+		break;
+	}
+}
+
+static void btf_renumber(struct btf_verifier_env *env, struct btf *base_btf)
+{
+	struct btf *btf = env->btf;
+	int i;
+
+	btf->start_id = base_btf->nr_types;
+	btf->start_str_off = base_btf->hdr.str_len;
+	btf->base_btf = base_btf;
+
+	for (i = 1; i < btf->nr_types; i++)
+		btf_type_renumber(env, btf->types[i]);
+	/* skip past unneeded void type (we use base id 0 instead) */
+	btf->types++;
+	btf->nr_types--;
+}
+
 static struct btf *btf_parse_module(const char *module_name, const void *data, unsigned int data_size)
 {
 	struct btf_verifier_env *env = NULL;
@@ -5933,10 +6181,29 @@  static struct btf *btf_parse_module(const char *module_name, const void *data, u
 	if (err)
 		goto errout;
 
+	if (btf_module_is_standalone(env)) {
+		/* BTF may be standalone; in that case BTF ids and strings
+		 * will all be self-referential.
+		 *
+		 * Later on, once we have checked all metas, we will
+		 * retain start id from  base BTF so it will look like
+		 * split BTF (but is self-contained); renumbering is done
+		 * also to give the split BTF-like appearance and not
+		 * confuse pahole which assumes split BTF for modules.
+		 */
+		btf->base_btf = NULL;
+		btf->start_id = 0;
+		btf->nr_types = 0;
+		btf->start_str_off = 0;
+		btf->standalone_btf = true;
+	}
 	err = btf_check_all_metas(env);
 	if (err)
 		goto errout;
 
+	if (btf->standalone_btf)
+		btf_renumber(env, base_btf);
+
 	err = btf_check_type_tags(env, btf, btf_nr_types(base_btf));
 	if (err)
 		goto errout;
@@ -7876,6 +8143,16 @@  static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook,
 
 	/* Concatenate the two sets */
 	memcpy(set->pairs + set->cnt, add_set->pairs, add_set->cnt * sizeof(set->pairs[0]));
+	if (btf->standalone_btf) {
+		u32 i;
+
+		/* renumber BTF ids since BTF is standalone and has been mapped to look
+		 * like split BTF, while BTF kfunc ids are still old unmapped values.
+		 */
+		for (i = set->cnt; i < set->cnt + add_set->cnt; i++)
+			set->pairs[i].id = btf_id_renumber(btf, set->pairs[i].id);
+	}
+
 	set->cnt += add_set->cnt;
 
 	sort(set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func, NULL);
@@ -7936,7 +8213,6 @@  static int bpf_prog_type_to_kfunc_hook(enum bpf_prog_type prog_type)
 	case BPF_PROG_TYPE_SYSCALL:
 		return BTF_KFUNC_HOOK_SYSCALL;
 	case BPF_PROG_TYPE_CGROUP_SKB:
-	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
 		return BTF_KFUNC_HOOK_CGROUP_SKB;
 	case BPF_PROG_TYPE_SCHED_ACT:
 		return BTF_KFUNC_HOOK_SCHED_ACT;
@@ -8005,7 +8281,14 @@  static int __register_btf_kfunc_id_set(enum btf_kfunc_hook hook,
 		return PTR_ERR(btf);
 
 	for (i = 0; i < kset->set->cnt; i++) {
-		ret = btf_check_kfunc_protos(btf, kset->set->pairs[i].id,
+		u32 kfunc_id = kset->set->pairs[i].id;
+
+		/* standalone BTF renumbers BTF ids to make them appear as split BTF;
+		 * resolve_btfids has the old BTF ids so we need to renumber here.
+		 */
+		if (btf->standalone_btf)
+			kfunc_id = btf_id_renumber(btf, kfunc_id);
+		ret = btf_check_kfunc_protos(btf, kfunc_id,
 					     kset->set->pairs[i].flags);
 		if (ret)
 			goto err_out;
@@ -8063,6 +8346,12 @@  static int btf_check_dtor_kfuncs(struct btf *btf, const struct btf_id_dtor_kfunc
 	for (i = 0; i < cnt; i++) {
 		dtor_btf_id = dtors[i].kfunc_btf_id;
 
+		/* standalone BTF renumbers BTF ids to make them appear as split BTF;
+		 * resolve_btfids has the old BTF ids so we need to renumber here.
+		 */
+		if (btf->standalone_btf)
+			dtor_btf_id = btf_id_renumber(btf, dtor_btf_id);
+
 		dtor_func = btf_type_by_id(btf, dtor_btf_id);
 		if (!dtor_func || !btf_type_is_func(dtor_func))
 			return -EINVAL;
@@ -8156,6 +8445,17 @@  int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_c
 	btf->dtor_kfunc_tab = tab;
 
 	memcpy(tab->dtors + tab->cnt, dtors, add_cnt * sizeof(tab->dtors[0]));
+	if (btf->standalone_btf) {
+		u32 i;
+
+		/* renumber BTF ids since BTF is standalone and has been mapped to look
+		 * like split BTF, while BTF dtor ids are still old unmapped values.
+		 */
+		for (i = tab->cnt; i < tab->cnt + add_cnt; i++) {
+			tab->dtors[i].btf_id = btf_id_renumber(btf, tab->dtors[i].btf_id);
+			tab->dtors[i].kfunc_btf_id = btf_id_renumber(btf, tab->dtors[i].kfunc_btf_id);
+		}
+	}
 	tab->cnt += add_cnt;
 
 	sort(tab->dtors, tab->cnt, sizeof(tab->dtors[0]), btf_id_cmp_func, NULL);