diff options
| -rw-r--r-- | Makefile | 43 | ||||
| -rw-r--r-- | buildid.c | 192 |
2 files changed, 230 insertions, 5 deletions
@@ -24,10 +24,13 @@ SBSIGN ?= sbsign prefix ?= /usr prefix := $(abspath $(prefix)) datadir ?= $(prefix)/share/ +PKGNAME ?= shim ESPROOTDIR ?= boot/efi/ EFIBOOTDIR ?= $(ESPROOTDIR)EFI/BOOT/ TARGETDIR ?= $(ESPROOTDIR)EFI/$(EFIDIR)/ DATATARGETDIR ?= $(datadir)/$(PKGNAME)/$(VERSION)$(DASHRELEASE)/$(ARCH_SUFFIX)/ +DEBUGINFO ?= $(prefix)/lib/debug/ +DEBUGSOURCE ?= $(prefix)/src/debug/ OSLABEL ?= $(EFIDIR) DEFAULT_LOADER ?= \\\\grub$(ARCH_SUFFIX).efi @@ -128,6 +131,7 @@ endif LDFLAGS = --hash-style=sysv -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIBDIR) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS) --build-id=sha1 TARGETS = $(SHIMNAME) +TARGETS += $(SHIMNAME).debug $(MMNAME).debug $(FBNAME).debug ifneq ($(origin ENABLE_SHIM_CERT),undefined) TARGETS += $(MMNAME).signed $(FBNAME).signed CFLAGS += -DENABLE_SHIM_CERT @@ -213,6 +217,9 @@ lib/lib.a: if [ ! -d lib ]; then mkdir lib ; fi $(MAKE) VPATH=$(TOPDIR)/lib TOPDIR=$(TOPDIR) CFLAGS="$(CFLAGS)" -C lib -f $(TOPDIR)/lib/Makefile +buildid : $(TOPDIR)/buildid.c + $(CC) -Og -g3 -Wall -Werror -Wextra -o $@ $< -lelf + $(BOOTCSVNAME) : @echo Making $@ @( printf "\xff\xfe" ; echo "$(SHIMNAME),$(OSLABEL),,This is the boot entry for $(OSLABEL)" | sed -z 's/./&\x00/g' ) > $@ @@ -226,10 +233,31 @@ ifeq ($(origin EFIDIR),undefined) endif install-deps : $(TARGETS) +install-deps : $(SHIMNAME).debug $(MMNAME).debug $(FBNAME).debug buildid install-deps : $(BOOTCSVNAME) +install-debugsource : install-deps + $(INSTALL) -d -m 0755 $(DESTDIR)/$(DEBUGSOURCE)/$(PKGNAME)-$(VERSION)$(DASHRELEASE) + find $(TOPDIR) -type f -a '(' -iname '*.c' -o -iname '*.h' -o -iname '*.S' ')' | while read file ; do \ + outfile=$$(echo $${file} | sed -e "s,^$(TOPDIR),,") ; \ + $(INSTALL) -d -m 0755 $(DESTDIR)/$(DEBUGSOURCE)/$(PKGNAME)-$(VERSION)$(DASHRELEASE)/$$(dirname $${outfile}) ; \ + $(INSTALL) -m 0644 $${file} $(DESTDIR)/$(DEBUGSOURCE)/$(PKGNAME)-$(VERSION)$(DASHRELEASE)/$${outfile} ; \ + done + +install-debuginfo : install-deps + $(INSTALL) -d -m 0755 $(DESTDIR)/ + $(INSTALL) -d -m 0755 $(DESTDIR)/$(DEBUGINFO)$(TARGETDIR)/ + @./buildid $(wildcard *.efi.debug) | while read file buildid ; do \ + first=$$(echo $${buildid} | cut -b -2) ; \ + rest=$$(echo $${buildid} | cut -b 3-) ; \ + $(INSTALL) -d -m 0755 $(DESTDIR)/$(DEBUGINFO).build-id/$${first}/ ;\ + $(INSTALL) -m 0644 $${file} $(DESTDIR)/$(DEBUGINFO)$(TARGETDIR) ; \ + ln -s ../../../../..$(DEBUGINFO)$(TARGETDIR)$${file} $(DESTDIR)/$(DEBUGINFO).build-id/$${first}/$${rest}.debug ;\ + ln -s ../../../.build-id/$${first}/$${rest} $(DESTDIR)/$(DEBUGINFO).build-id/$${first}/$${rest} ;\ + done + install : | install-check -install : install-deps +install : install-deps install-debuginfo install-debugsource $(INSTALL) -d -m 0755 $(DESTDIR)/ $(INSTALL) -d -m 0700 $(DESTDIR)/$(ESPROOTDIR) $(INSTALL) -d -m 0755 $(DESTDIR)/$(EFIBOOTDIR) @@ -263,17 +291,22 @@ ifneq ($(OBJCOPY_GTE224),1) $(error objcopy >= 2.24 is required) endif $(OBJCOPY) -j .text -j .sdata -j .data -j .data.ident \ - -j .dynamic -j .dynsym -j .rel* \ + -j .dynamic -j .dynsym -j .rel* \ -j .rela* -j .reloc -j .eh_frame \ -j .vendor_cert \ - $(FORMAT) $^ $@ + $(FORMAT) $^ $@ + +%.efi.debug : %.so +ifneq ($(OBJCOPY_GTE224),1) + $(error objcopy >= 2.24 is required) +endif $(OBJCOPY) -j .text -j .sdata -j .data \ - -j .dynamic -j .dynsym -j .rel* \ + -j .dynamic -j .dynsym -j .rel* \ -j .rela* -j .reloc -j .eh_frame \ -j .debug_info -j .debug_abbrev -j .debug_aranges \ -j .debug_line -j .debug_str -j .debug_ranges \ -j .note.gnu.build-id \ - $(FORMAT) $^ $@.debug + $^ $@ ifneq ($(origin ENABLE_SBSIGN),undefined) %.efi.signed: %.efi shim.key shim.crt diff --git a/buildid.c b/buildid.c new file mode 100644 index 00000000..b27aa1fe --- /dev/null +++ b/buildid.c @@ -0,0 +1,192 @@ +/* + * Walk a list of input files, printing the name and buildid of any file + * that has one. + * + * This program is licensed under the GNU Public License version 2. + */ + +#include <err.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <getopt.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <libelf.h> +#include <gelf.h> + +static Elf_Scn *get_scn_named(Elf * elf, char *goal, GElf_Shdr * shdrp_out) +{ + int rc; + size_t shstrndx = -1; + int scn_no = 0; + Elf_Scn *scn = NULL; + GElf_Shdr shdr_data, *shdrp; + + shdrp = shdrp_out ? shdrp_out : &shdr_data; + + rc = elf_getshdrstrndx(elf, &shstrndx); + if (rc < 0) + return NULL; + + do { + GElf_Shdr *shdr; + char *name; + + scn = elf_getscn(elf, ++scn_no); + if (!scn) + break; + + shdr = gelf_getshdr(scn, shdrp); + if (!shdr) + /* + * the binary is malformed, but hey, maybe the next + * one is fine, why not... + */ + continue; + + name = elf_strptr(elf, shstrndx, shdr->sh_name); + if (name && !strcmp(name, goal)) + return scn; + } while (scn != NULL); + return NULL; +} + +static void *get_buildid(Elf * elf, size_t * sz) +{ + Elf_Scn *scn; + size_t notesz; + size_t offset = 0; + Elf_Data *data; + GElf_Shdr shdr; + + scn = get_scn_named(elf, ".note.gnu.build-id", &shdr); + if (!scn) + return NULL; + + data = elf_getdata(scn, NULL); + if (!data) + return NULL; + + do { + size_t nameoff; + size_t descoff; + GElf_Nhdr nhdr; + char *name; + + notesz = gelf_getnote(data, offset, &nhdr, &nameoff, &descoff); + if (!notesz) + break; + offset += notesz; + + if (nhdr.n_type != NT_GNU_BUILD_ID) + continue; + + name = data->d_buf + nameoff; + if (!name || strcmp(name, ELF_NOTE_GNU)) + continue; + + *sz = nhdr.n_descsz; + return data->d_buf + descoff; + } while (notesz); + return NULL; +} + +static void data2hex(uint8_t * data, size_t ds, char *str) +{ + const char hex[] = "0123456789abcdef"; + int s; + unsigned int d; + for (d = 0, s = 0; d < ds; d += 1, s += 2) { + str[s + 0] = hex[(data[d] >> 4) & 0x0f]; + str[s + 1] = hex[(data[d] >> 0) & 0x0f]; + } + str[s] = '\0'; +} + +static void handle_one(char *f) +{ + int fd; + Elf *elf; + char *b = NULL; + size_t sz; + uint8_t *data; + + if (!strcmp(f, "-")) { + fd = STDIN_FILENO; + + if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) + errx(1, "Couldn't read ELF data from \"%s\"", f); + } else { + if ((fd = open(f, O_RDONLY)) < 0) + err(1, "Couldn't open \"%s\"", f); + + if ((elf = elf_begin(fd, ELF_C_READ_MMAP, NULL)) == NULL) + errx(1, "Couldn't read ELF data from \"%s\"", f); + } + + data = get_buildid(elf, &sz); + if (data) { + b = alloca(sz * 2 + 1); + data2hex(data, sz, b); + if (b) { + write(1, f, strlen(f)); + write(1, " ", 1); + write(1, b, strlen(b)); + write(1, "\n", 1); + } + } + elf_end(elf); + close(fd); +} + +static void + __attribute__ ((__noreturn__)) + usage(int status) +{ + FILE *out = status ? stderr : stdout; + + fprintf(out, "Usage: buildid [ flags | file0 [file1 [.. fileN]]]\n"); + fprintf(out, "Flags:\n"); + fprintf(out, " -h Print this help text and exit\n"); + + exit(status); +} + +int main(int argc, char **argv) +{ + int i; + struct option options[] = { + {.name = "help", + .val = '?', + }, + {.name = "usage", + .val = '?', + }, + {.name = ""} + }; + int longindex = -1; + + while ((i = getopt_long(argc, argv, "h", options, &longindex)) != -1) { + switch (i) { + case 'h': + case '?': + usage(longindex == -1 ? 1 : 0); + break; + } + } + + elf_version(EV_CURRENT); + + if (optind == argc) + usage(1); + + for (i = optind; i < argc; i++) + handle_one(argv[i]); + + return 0; +} + +// vim:fenc=utf-8:tw=75 |
