From 838ebbcf92352217ea7ed16e0894ea585a357f88 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 14 Dec 2016 16:04:26 -0800 Subject: Use dl_iterate_phdr() instead of a linker script. According to Mike Frysinger [1] it is not reliable to read ELF sections at runtime, which the previous method involving the linker script was doing. Instead, use dl_iterate_phdr() to find the build id. [1] https://sourceware.org/ml/binutils/2016-12/msg00207.html --- Makefile | 4 +-- build-id.c | 96 ++++++++++++++++++++++++++++++++++++++---------------------- build-id.h | 23 +++++---------- build-id.lds | 9 ------ so-test.c | 20 +++---------- test.c | 18 +++--------- 6 files changed, 79 insertions(+), 91 deletions(-) delete mode 100644 build-id.lds diff --git a/Makefile b/Makefile index 798da5b..5c4295f 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -LDFLAGS = -Wl,--build-id=sha1 -Wl,--default-script=build-id.lds +LDFLAGS = -Wl,--build-id=sha1 all: build-id so-build-id @@ -33,7 +33,7 @@ shared-build-id.o: build-id.c $(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -c $^ -o $@ libbuild-id.so: shared-build-id.o - $(CC) -Wl,-Bsymbolic $(LDFLAGS) -shared $^ -o $@ + $(CC) $(LDFLAGS) -shared $^ -o $@ clean: rm -f build-id so-build-id libbuild-id.so *.o diff --git a/build-id.c b/build-id.c index 94b2e5c..e1df0c7 100644 --- a/build-id.c +++ b/build-id.c @@ -22,61 +22,87 @@ * IN THE SOFTWARE. */ -#include +#define _GNU_SOURCE +#include #include +#include #include #include "build-id.h" -extern const ElfW(Nhdr) __note_gnu_build_id_start[] __attribute__((weak)); -extern const ElfW(Nhdr) __note_gnu_build_id_end[] __attribute__((weak)); +#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1)) -void -so_print(void) -{ - extern char etext, edata, end; - printf("Shared object:\n"); - printf(" program text (etext) %10p\n", &etext); - printf(" initialized data (edata) %10p\n", &edata); - printf(" uninitialized data (end) %10p\n", &end); - printf(" note section start %10p\n", __note_gnu_build_id_start); - printf(" note section end %10p\n", __note_gnu_build_id_end); -} +struct note { + ElfW(Nhdr) nhdr; + + char name[4]; + uint8_t build_id[0]; +}; -const ElfW(Nhdr) * -build_id_find_nhdr(void) +struct callback_data { + const char *name; + struct note *note; +}; + +static int +build_id_find_nhdr_callback(struct dl_phdr_info *info, size_t size, void *data_) { - const ElfW(Nhdr) *nhdr = (void *)__note_gnu_build_id_start; + struct callback_data *data = data_; - if (__note_gnu_build_id_start >= __note_gnu_build_id_end) { - fprintf(stderr, "No .note section\n"); - return NULL; - } + if (strcmp(info->dlpi_name, data->name) != 0) + return 0; + + for (unsigned i = 0; i < info->dlpi_phnum; i++) { + if (info->dlpi_phdr[i].p_type != PT_NOTE) + continue; - while (nhdr->n_type != NT_GNU_BUILD_ID) - { - nhdr = (ElfW(Nhdr) *) - ((intptr_t)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz); + struct note *note = (void *)(info->dlpi_addr + + info->dlpi_phdr[i].p_vaddr); + ptrdiff_t len = info->dlpi_phdr[i].p_filesz; - if (nhdr >= __note_gnu_build_id_end) { - fprintf(stderr, "No .note.gnu.build-id section found\n"); - return NULL; + while (len >= sizeof(struct note)) { + if (note->nhdr.n_type == NT_GNU_BUILD_ID && + note->nhdr.n_descsz != 0 && + note->nhdr.n_namesz == 4 && + memcmp(note->name, "GNU", 4) == 0) { + data->note = note; + return 1; + } + + size_t offset = sizeof(ElfW(Nhdr)) + + ALIGN(note->nhdr.n_namesz, 4) + + ALIGN(note->nhdr.n_descsz, 4); + note = (struct note *)((char *)note + offset); + len -= offset; } } - return nhdr; + return 0; +} + +const struct note * +build_id_find_nhdr(const char *name) +{ + struct callback_data data = { + .name = name, + .note = NULL, + }; + + if (dl_iterate_phdr(build_id_find_nhdr_callback, &data)) { + return data.note; + } else { + return NULL; + } } ElfW(Word) -build_id_length(const ElfW(Nhdr) *nhdr) +build_id_length(const struct note *note) { - return nhdr->n_descsz; + return note->nhdr.n_descsz; } void -build_id_read(const ElfW(Nhdr) *nhdr, unsigned char *build_id) +build_id_read(const struct note *note, unsigned char *build_id) { - memcpy(build_id, - (unsigned char *)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz, - nhdr->n_descsz); + memcpy(build_id, note->build_id, note->nhdr.n_descsz); } diff --git a/build-id.h b/build-id.h index 7a51c1e..03e2684 100644 --- a/build-id.h +++ b/build-id.h @@ -22,24 +22,17 @@ * IN THE SOFTWARE. */ -#include -#include -#include +#define _GNU_SOURCE +#include +#include -#if __x86_64__ -# define ElfW(type) Elf64_##type -#else -# define ElfW(type) Elf32_##type -#endif +struct note; -void -so_print(void); - -const ElfW(Nhdr) * -build_id_find_nhdr(void); +const struct note * +build_id_find_nhdr(const char *name); ElfW(Word) -build_id_length(const ElfW(Nhdr) *nhdr); +build_id_length(const struct note *note); void -build_id_read(const ElfW(Nhdr) *nhdr, unsigned char *build_id); +build_id_read(const struct note *note, unsigned char *build_id); diff --git a/build-id.lds b/build-id.lds deleted file mode 100644 index 63a23f2..0000000 --- a/build-id.lds +++ /dev/null @@ -1,9 +0,0 @@ -SECTIONS -{ - build-id : { - PROVIDE(__note_gnu_build_id_start = .); - *(.note.gnu.build-id); - PROVIDE(__note_gnu_build_id_end = .); - } -} -INSERT AFTER .note.gnu.build-id; diff --git a/so-test.c b/so-test.c index 0c5d74a..095fbef 100644 --- a/so-test.c +++ b/so-test.c @@ -30,29 +30,17 @@ int main(int argc, char *argv[]) { - extern char etext, edata, end; - extern const char __note_gnu_build_id_end[] __attribute__((weak)); - extern const char __note_gnu_build_id_start[] __attribute__((weak)); - printf("Executable:\n"); - printf(" program text (etext) %10p\n", &etext); - printf(" initialized data (edata) %10p\n", &edata); - printf(" uninitialized data (end) %10p\n", &end); - printf(" note section start %10p\n", __note_gnu_build_id_start); - printf(" note section end %10p\n", __note_gnu_build_id_end); - - so_print(); - - const ElfW(Nhdr) *nhdr = build_id_find_nhdr(); - if (!nhdr) + const struct note *note = build_id_find_nhdr("./libbuild-id.so"); + if (!note) return -1; - ElfW(Word) len = build_id_length(nhdr); + ElfW(Word) len = build_id_length(note); unsigned char *build_id = malloc(len * sizeof(char)); if (!build_id) return -1; - build_id_read(nhdr, build_id); + build_id_read(note, build_id); printf("Build ID: "); for (ElfW(Word) i = 0; i < len; i++) { diff --git a/test.c b/test.c index e8dae35..fbea6b4 100644 --- a/test.c +++ b/test.c @@ -30,27 +30,17 @@ int main(int argc, char *argv[]) { - extern char etext, edata, end; - extern const char __note_gnu_build_id_end[] __attribute__((weak)); - extern const char __note_gnu_build_id_start[] __attribute__((weak)); - printf("Executable:\n"); - printf(" program text (etext) %10p\n", &etext); - printf(" initialized data (edata) %10p\n", &edata); - printf(" uninitialized data (end) %10p\n", &end); - printf(" note section start %10p\n", __note_gnu_build_id_start); - printf(" note section end %10p\n", __note_gnu_build_id_end); - - const ElfW(Nhdr) *nhdr = build_id_find_nhdr(); - if (!nhdr) + const struct note *note = build_id_find_nhdr(""); + if (!note) return -1; - ElfW(Word) len = build_id_length(nhdr); + ElfW(Word) len = build_id_length(note); unsigned char *build_id = malloc(len * sizeof(char)); if (!build_id) return -1; - build_id_read(nhdr, build_id); + build_id_read(note, build_id); printf("Build ID: "); for (ElfW(Word) i = 0; i < len; i++) { -- cgit v1.2.3