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.

resolve_btfids: Implement --patch_btfids

Recent changes in BTF generation [1] rely on ${OBJCOPY} command to
update .BTF_ids section data in target ELF files.

This exposed a bug in llvm-objcopy --update-section code path, that
may lead to corruption of a target ELF file. Specifically, because of
the bug st_shndx of some symbols may be (incorrectly) set to 0xffff
(SHN_XINDEX) [2][3].

While there is a pending fix for LLVM, it'll take some time before it
lands (likely in 22.x). And the kernel build must keep working with
older LLVM toolchains in the foreseeable future.

Using GNU objcopy for .BTF_ids update would work, but it would require
changes to LLVM-based build process, likely breaking existing build
environments as discussed in [2].

To work around llvm-objcopy bug, implement --patch_btfids code path in
resolve_btfids as a drop-in replacement for:

${OBJCOPY} --update-section .BTF_ids=${btf_ids} ${elf}

Which works specifically for .BTF_ids section:

${RESOLVE_BTFIDS} --patch_btfids ${btf_ids} ${elf}

This feature in resolve_btfids can be removed at some point in the
future, when llvm-objcopy with a relevant bugfix becomes common.

[1] https://lore.kernel.org/bpf/20251219181321.1283664-1-ihor.solodrai@linux.dev/
[2] https://lore.kernel.org/bpf/20251224005752.201911-1-ihor.solodrai@linux.dev/
[3] https://github.com/llvm/llvm-project/issues/168060#issuecomment-3533552952

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Link: https://lore.kernel.org/r/20251231012558.1699758-1-ihor.solodrai@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Ihor Solodrai and committed by
Alexei Starovoitov
1a8fa7fa c0e4a193

+120 -3
+1 -1
scripts/gen-btf.sh
··· 123 123 fi 124 124 local btf_ids="${ELF_FILE}.BTF_ids" 125 125 if [ -f "${btf_ids}" ]; then 126 - ${OBJCOPY} --update-section .BTF_ids=${btf_ids} ${ELF_FILE} 126 + ${RESOLVE_BTFIDS} --patch_btfids ${btf_ids} ${ELF_FILE} 127 127 fi 128 128 } 129 129
+117
tools/bpf/resolve_btfids/main.c
··· 862 862 return 0; 863 863 } 864 864 865 + /* 866 + * Patch the .BTF_ids section of an ELF file with data from provided file. 867 + * Equivalent to: objcopy --update-section .BTF_ids=<btfids> <elf> 868 + * 869 + * 1. Find .BTF_ids section in the ELF 870 + * 2. Verify that blob file size matches section size 871 + * 3. Update section data buffer with blob data 872 + * 4. Write the ELF file 873 + */ 874 + static int patch_btfids(const char *btfids_path, const char *elf_path) 875 + { 876 + Elf_Scn *scn = NULL; 877 + FILE *btfids_file; 878 + size_t shdrstrndx; 879 + int fd, err = -1; 880 + Elf_Data *data; 881 + struct stat st; 882 + GElf_Shdr sh; 883 + char *name; 884 + Elf *elf; 885 + 886 + elf_version(EV_CURRENT); 887 + 888 + fd = open(elf_path, O_RDWR, 0666); 889 + if (fd < 0) { 890 + pr_err("FAILED to open %s: %s\n", elf_path, strerror(errno)); 891 + return -1; 892 + } 893 + 894 + elf = elf_begin(fd, ELF_C_RDWR_MMAP, NULL); 895 + if (!elf) { 896 + close(fd); 897 + pr_err("FAILED cannot create ELF descriptor: %s\n", elf_errmsg(-1)); 898 + return -1; 899 + } 900 + 901 + elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT); 902 + 903 + if (elf_getshdrstrndx(elf, &shdrstrndx) != 0) { 904 + pr_err("FAILED cannot get shdr str ndx\n"); 905 + goto out; 906 + } 907 + 908 + while ((scn = elf_nextscn(elf, scn)) != NULL) { 909 + 910 + if (gelf_getshdr(scn, &sh) != &sh) { 911 + pr_err("FAILED to get section header\n"); 912 + goto out; 913 + } 914 + 915 + name = elf_strptr(elf, shdrstrndx, sh.sh_name); 916 + if (!name) 917 + continue; 918 + 919 + if (strcmp(name, BTF_IDS_SECTION) == 0) 920 + break; 921 + } 922 + 923 + if (!scn) { 924 + pr_err("FAILED: section %s not found in %s\n", BTF_IDS_SECTION, elf_path); 925 + goto out; 926 + } 927 + 928 + data = elf_getdata(scn, NULL); 929 + if (!data) { 930 + pr_err("FAILED to get %s section data from %s\n", BTF_IDS_SECTION, elf_path); 931 + goto out; 932 + } 933 + 934 + if (stat(btfids_path, &st) < 0) { 935 + pr_err("FAILED to stat %s: %s\n", btfids_path, strerror(errno)); 936 + goto out; 937 + } 938 + 939 + if ((size_t)st.st_size != data->d_size) { 940 + pr_err("FAILED: size mismatch - %s section in %s is %zu bytes, %s is %zu bytes\n", 941 + BTF_IDS_SECTION, elf_path, data->d_size, btfids_path, (size_t)st.st_size); 942 + goto out; 943 + } 944 + 945 + btfids_file = fopen(btfids_path, "rb"); 946 + if (!btfids_file) { 947 + pr_err("FAILED to open %s: %s\n", btfids_path, strerror(errno)); 948 + goto out; 949 + } 950 + 951 + pr_debug("Copying data from %s to %s section of %s (%zu bytes)\n", 952 + btfids_path, BTF_IDS_SECTION, elf_path, data->d_size); 953 + 954 + if (fread(data->d_buf, data->d_size, 1, btfids_file) != 1) { 955 + pr_err("FAILED to read %s\n", btfids_path); 956 + fclose(btfids_file); 957 + goto out; 958 + } 959 + fclose(btfids_file); 960 + 961 + elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY); 962 + if (elf_update(elf, ELF_C_WRITE) < 0) { 963 + pr_err("FAILED to update ELF file %s\n", elf_path); 964 + goto out; 965 + } 966 + 967 + err = 0; 968 + out: 969 + elf_end(elf); 970 + close(fd); 971 + 972 + return err; 973 + } 974 + 865 975 static const char * const resolve_btfids_usage[] = { 866 976 "resolve_btfids [<options>] <ELF object>", 977 + "resolve_btfids --patch_btfids <.BTF_ids file> <ELF object>", 867 978 NULL 868 979 }; 869 980 ··· 991 880 .funcs = RB_ROOT, 992 881 .sets = RB_ROOT, 993 882 }; 883 + const char *btfids_path = NULL; 994 884 bool fatal_warnings = false; 995 885 char out_path[PATH_MAX]; 996 886 ··· 1006 894 "turn warnings into errors"), 1007 895 OPT_BOOLEAN(0, "distill_base", &obj.distill_base, 1008 896 "distill --btf_base and emit .BTF.base section data"), 897 + OPT_STRING(0, "patch_btfids", &btfids_path, "file", 898 + "path to .BTF_ids section data blob to patch into ELF file"), 1009 899 OPT_END() 1010 900 }; 1011 901 int err = -1; ··· 1018 904 usage_with_options(resolve_btfids_usage, btfid_options); 1019 905 1020 906 obj.path = argv[0]; 907 + 908 + if (btfids_path) 909 + return patch_btfids(btfids_path, obj.path); 1021 910 1022 911 if (load_btf(&obj)) 1023 912 goto out;
+1 -1
tools/testing/selftests/bpf/Makefile
··· 657 657 $$(if $$(TEST_NEEDS_BTFIDS), \ 658 658 $$(call msg,BTFIDS,$(TRUNNER_BINARY),$$@) \ 659 659 $(RESOLVE_BTFIDS) --btf $(TRUNNER_OUTPUT)/btf_data.bpf.o $$@; \ 660 - $(OBJCOPY) --update-section .BTF_ids=$$@.BTF_ids $$@) 660 + $(RESOLVE_BTFIDS) --patch_btfids $$@.BTF_ids $$@) 661 661 662 662 $(TRUNNER_TEST_OBJS:.o=.d): $(TRUNNER_OUTPUT)/%.test.d: \ 663 663 $(TRUNNER_TESTS_DIR)/%.c \