]> git.proxmox.com Git - efi-boot-shim.git/blame - buildid.c
Improve how the dbx hashes are handled
[efi-boot-shim.git] / buildid.c
CommitLineData
aedb8470
PJ
1// SPDX-License-Identifier: BSD-2-Clause-Patent
2
82c3e007
PJ
3/*
4 * Walk a list of input files, printing the name and buildid of any file
5 * that has one.
82c3e007
PJ
6 */
7
8#include <err.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <fcntl.h>
12#include <getopt.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16#include <unistd.h>
17#include <libelf.h>
18#include <gelf.h>
19
20static Elf_Scn *get_scn_named(Elf * elf, char *goal, GElf_Shdr * shdrp_out)
21{
22 int rc;
23 size_t shstrndx = -1;
24 int scn_no = 0;
25 Elf_Scn *scn = NULL;
26 GElf_Shdr shdr_data, *shdrp;
27
28 shdrp = shdrp_out ? shdrp_out : &shdr_data;
29
30 rc = elf_getshdrstrndx(elf, &shstrndx);
31 if (rc < 0)
32 return NULL;
33
34 do {
35 GElf_Shdr *shdr;
36 char *name;
37
38 scn = elf_getscn(elf, ++scn_no);
39 if (!scn)
40 break;
41
42 shdr = gelf_getshdr(scn, shdrp);
43 if (!shdr)
44 /*
45 * the binary is malformed, but hey, maybe the next
46 * one is fine, why not...
47 */
48 continue;
49
50 name = elf_strptr(elf, shstrndx, shdr->sh_name);
51 if (name && !strcmp(name, goal))
52 return scn;
53 } while (scn != NULL);
54 return NULL;
55}
56
57static void *get_buildid(Elf * elf, size_t * sz)
58{
59 Elf_Scn *scn;
60 size_t notesz;
61 size_t offset = 0;
62 Elf_Data *data;
63 GElf_Shdr shdr;
64
65 scn = get_scn_named(elf, ".note.gnu.build-id", &shdr);
66 if (!scn)
67 return NULL;
68
69 data = elf_getdata(scn, NULL);
70 if (!data)
71 return NULL;
72
73 do {
74 size_t nameoff;
75 size_t descoff;
76 GElf_Nhdr nhdr;
77 char *name;
78
79 notesz = gelf_getnote(data, offset, &nhdr, &nameoff, &descoff);
80 if (!notesz)
81 break;
82 offset += notesz;
83
84 if (nhdr.n_type != NT_GNU_BUILD_ID)
85 continue;
86
87 name = data->d_buf + nameoff;
88 if (!name || strcmp(name, ELF_NOTE_GNU))
89 continue;
90
91 *sz = nhdr.n_descsz;
92 return data->d_buf + descoff;
93 } while (notesz);
94 return NULL;
95}
96
97static void data2hex(uint8_t * data, size_t ds, char *str)
98{
99 const char hex[] = "0123456789abcdef";
100 int s;
101 unsigned int d;
102 for (d = 0, s = 0; d < ds; d += 1, s += 2) {
103 str[s + 0] = hex[(data[d] >> 4) & 0x0f];
104 str[s + 1] = hex[(data[d] >> 0) & 0x0f];
105 }
106 str[s] = '\0';
107}
108
109static void handle_one(char *f)
110{
111 int fd;
112 Elf *elf;
113 char *b = NULL;
114 size_t sz;
115 uint8_t *data;
cc08ed0e 116 ssize_t written;
82c3e007
PJ
117
118 if (!strcmp(f, "-")) {
119 fd = STDIN_FILENO;
120
121 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
122 errx(1, "Couldn't read ELF data from \"%s\"", f);
123 } else {
124 if ((fd = open(f, O_RDONLY)) < 0)
125 err(1, "Couldn't open \"%s\"", f);
126
127 if ((elf = elf_begin(fd, ELF_C_READ_MMAP, NULL)) == NULL)
128 errx(1, "Couldn't read ELF data from \"%s\"", f);
129 }
130
131 data = get_buildid(elf, &sz);
132 if (data) {
133 b = alloca(sz * 2 + 1);
134 data2hex(data, sz, b);
135 if (b) {
cc08ed0e
MTL
136 written = write(1, f, strlen(f));
137 if (written < 0)
138 errx(1, "Error writing build id");
139 written = write(1, " ", 1);
140 written = write(1, b, strlen(b));
141 if (written < 0)
142 errx(1, "Error writing build id");
143 written = write(1, "\n", 1);
82c3e007
PJ
144 }
145 }
146 elf_end(elf);
147 close(fd);
148}
149
150static void
151 __attribute__ ((__noreturn__))
152 usage(int status)
153{
154 FILE *out = status ? stderr : stdout;
155
156 fprintf(out, "Usage: buildid [ flags | file0 [file1 [.. fileN]]]\n");
157 fprintf(out, "Flags:\n");
158 fprintf(out, " -h Print this help text and exit\n");
159
160 exit(status);
161}
162
163int main(int argc, char **argv)
164{
165 int i;
166 struct option options[] = {
167 {.name = "help",
168 .val = '?',
169 },
170 {.name = "usage",
171 .val = '?',
172 },
173 {.name = ""}
174 };
175 int longindex = -1;
176
177 while ((i = getopt_long(argc, argv, "h", options, &longindex)) != -1) {
178 switch (i) {
179 case 'h':
180 case '?':
181 usage(longindex == -1 ? 1 : 0);
182 break;
183 }
184 }
185
186 elf_version(EV_CURRENT);
187
188 if (optind == argc)
189 usage(1);
190
191 for (i = optind; i < argc; i++)
192 handle_one(argv[i]);
193
194 return 0;
195}
196
197// vim:fenc=utf-8:tw=75