From: Lucas De Marchi Date: Wed, 25 Mar 2026 04:34:28 +0000 (-0500) Subject: libkmod: Add helper to read .note.gnu.build-id section X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=bbbfcd8f3d9640b17ca51cc1bc68615da34dbe18;p=thirdparty%2Fkmod.git libkmod: Add helper to read .note.gnu.build-id section Read the .note.gnu.build-id section so it can be displayed by modinfo in a future change. For now this is only added to pretty-print the id, but later can be refactored to easily compare with the section dump from /sys/module//.note.gnu.build-id The section in the elf is potentially available since kernel 4.10 (if toolchain supports it) and became unconditional since commit 89ff7131f78a ("kbuild: add --hash-style= and --build-id unconditionally") since minimum toolchain versions got raised. Signed-off-by: Lucas De Marchi Reviewed-by: Emil Velikov Link: https://github.com/kmod-project/kmod/pull/432 --- diff --git a/libkmod/libkmod-elf.c b/libkmod/libkmod-elf.c index 7fe6a29..9d500f1 100644 --- a/libkmod/libkmod-elf.c +++ b/libkmod/libkmod-elf.c @@ -32,6 +32,7 @@ enum kmod_elf_section { KMOD_ELF_SECTION_STRTAB, KMOD_ELF_SECTION_SYMTAB, KMOD_ELF_SECTION_VERSIONS, + KMOD_ELF_SECTION_BUILD_ID, KMOD_ELF_SECTION_MAX, }; @@ -41,6 +42,7 @@ static const char *const section_name_map[] = { [KMOD_ELF_SECTION_STRTAB] = ".strtab", [KMOD_ELF_SECTION_SYMTAB] = ".symtab", [KMOD_ELF_SECTION_VERSIONS] = "__versions", + [KMOD_ELF_SECTION_BUILD_ID] = ".note.gnu.build-id", }; struct kmod_elf { @@ -1247,3 +1249,62 @@ int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, free(visited_versions); return count; } + +#ifndef NT_GNU_BUILD_ID +#define NT_GNU_BUILD_ID 3 +#endif + +/* + * Read the .notes.gnu.build-id section that is added by the linker via --build-id. The + * section format follows the one defined in shared/elf-note.h, with name == "GNU\0", + * type == NT_GNU_BUILD_ID and desc being the hash. + */ +int kmod_elf_get_build_id(const struct kmod_elf *elf, const void **hash, size_t *hash_len) +{ + uint32_t namesz, descsz, type; + uint64_t off, size; + const char *name; + + off = elf->sections[KMOD_ELF_SECTION_BUILD_ID].offset; + size = elf->sections[KMOD_ELF_SECTION_BUILD_ID].size; + if (off == 0 || size == 0) + /* + * Conditionally available since 4.10 if toolchain supports it. + * Unconditionally available since 5.10: + * kernel- commit 89ff7131f78a ("kbuild: add --hash-style= and + * --build-id unconditionally"). Just return an error and don't + * log anything. + */ + return -ENODATA; + + if (size < 3 * sizeof(uint32_t)) { + ELFDBG(elf, "build-id section is too small: %" PRIu64 "\n", size); + return -EINVAL; + } + + namesz = elf_get_u32(elf, off); + off += sizeof(uint32_t); + descsz = elf_get_u32(elf, off); + off += sizeof(uint32_t); + type = elf_get_u32(elf, off); + off += sizeof(uint32_t); + + if (size < 3 * sizeof(uint32_t) + namesz + descsz) { + ELFDBG(elf, "build-id section is too small: %" PRIu64 "\n", size); + return -EINVAL; + } + + name = elf_get_mem(elf, off); + + if (type != NT_GNU_BUILD_ID || !streq(name, "GNU")) { + ELFDBG(elf, "Invalid build-id section: type %" PRIu32 ", name %.3s\n", + type, name); + return -EINVAL; + } + + off += namesz; + *hash = elf_get_mem(elf, off); + *hash_len = descsz; + + return 0; +} diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h index cc681e2..e856662 100644 --- a/libkmod/libkmod-internal.h +++ b/libkmod/libkmod-internal.h @@ -156,6 +156,7 @@ _must_check_ _nonnull_all_ int kmod_elf_get_modinfo_strings(const struct kmod_el _must_check_ _nonnull_all_ int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion **array); _must_check_ _nonnull_all_ int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array); _must_check_ _nonnull_all_ int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array); +_must_check_ _nonnull_all_ int kmod_elf_get_build_id(const struct kmod_elf *elf, const void **hash, size_t *hash_len); _must_check_ _nonnull_all_ int kmod_elf_strip(const struct kmod_elf *elf, unsigned int flags, const void **stripped); /*