Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
4 : : *
5 : : * SPDX-License-Identifier: BSD-2-Clause
6 : : */
7 : :
8 : : #ifdef HAVE_CONFIG_H
9 : : #include "pkg_config.h"
10 : : #endif
11 : :
12 : : #ifdef HAVE_SYS_ENDIAN_H
13 : : #include <sys/endian.h>
14 : : #elif HAVE_ENDIAN_H
15 : : #include <endian.h>
16 : : #elif HAVE_MACHINE_ENDIAN_H
17 : : #include <machine/endian.h>
18 : : #endif
19 : : #include <sys/types.h>
20 : : #if defined(HAVE_SYS_ELF_COMMON_H) && !defined(__DragonFly__)
21 : : #include <sys/elf_common.h>
22 : : #endif
23 : : #include <sys/stat.h>
24 : :
25 : : #include <assert.h>
26 : : #include <dlfcn.h>
27 : : #include <fcntl.h>
28 : : #include <gelf.h>
29 : : #include <libgen.h>
30 : : #if defined(HAVE_LINK_H) && !defined(__DragonFly__) && defined(HAVE_LIBELF)
31 : : #include <link.h>
32 : : #endif
33 : : #include <paths.h>
34 : : #include <stdbool.h>
35 : : #include <string.h>
36 : : #include <unistd.h>
37 : : #ifdef HAVE_LIBELF
38 : : #include <libelf.h>
39 : : #endif
40 : :
41 : : #include <bsd_compat.h>
42 : :
43 : : #include "pkg.h"
44 : : #include "private/pkg.h"
45 : : #include "private/pkg_abi.h"
46 : : #include "private/event.h"
47 : : #include "private/binfmt.h"
48 : :
49 : : #ifndef NT_ABI_TAG
50 : : #define NT_ABI_TAG 1
51 : : #endif
52 : :
53 : : #define NT_VERSION 1
54 : : #define NT_ARCH 2
55 : : #define NT_GNU_ABI_TAG 1
56 : :
57 : : #ifndef roundup2
58 : : #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
59 : : #endif
60 : :
61 : : static void elf_parse_abi(Elf *elf, GElf_Ehdr *ehdr, struct pkg_abi *abi);
62 : :
63 : : #ifndef HAVE_ELF_NOTE
64 : : typedef Elf32_Nhdr Elf_Note;
65 : : #endif
66 : :
67 : : static int
68 : 250 : analyse_elf(struct pkg *pkg, const char *fpath)
69 : : {
70 : 250 : int ret = EPKG_OK;
71 : :
72 : 250 : pkg_debug(1, "analysing elf %s", fpath);
73 : :
74 : : struct stat sb;
75 [ + - ]: 250 : if (lstat(fpath, &sb) != 0)
76 : 0 : pkg_emit_errno("fstat() failed for", fpath);
77 : : /* ignore empty files and non regular files */
78 [ + + + + ]: 250 : if (sb.st_size == 0 || !S_ISREG(sb.st_mode))
79 : 157 : return (EPKG_END); /* Empty file or sym-link: no results */
80 : :
81 : 93 : int fd = open(fpath, O_RDONLY, 0);
82 [ + - ]: 93 : if (fd < 0) {
83 : 0 : return (EPKG_FATAL);
84 : : }
85 : :
86 [ + - ]: 93 : if (elf_version(EV_CURRENT) == EV_NONE) {
87 : 0 : pkg_emit_error("ELF library initialization failed: %s",
88 : 0 : elf_errmsg(-1));
89 : 0 : return (EPKG_FATAL);
90 : : }
91 : :
92 : 93 : Elf *e = elf_begin(fd, ELF_C_READ, NULL);
93 [ + - ]: 93 : if (e == NULL) {
94 : 0 : ret = EPKG_FATAL;
95 : 0 : pkg_debug(1, "elf_begin() for %s failed: %s", fpath,
96 : 0 : elf_errmsg(-1));
97 : 0 : goto cleanup;
98 : : }
99 : :
100 [ + + ]: 93 : if (elf_kind(e) != ELF_K_ELF) {
101 : : /* Not an elf file: no results */
102 : 68 : ret = EPKG_END;
103 : 68 : pkg_debug(1, "not an elf");
104 : 68 : goto cleanup;
105 : : }
106 : :
107 [ + - ]: 25 : if (ctx.developer_mode)
108 : 0 : pkg->flags |= PKG_CONTAINS_ELF_OBJECTS;
109 : :
110 : : GElf_Ehdr elfhdr;
111 [ + - ]: 25 : if (gelf_getehdr(e, &elfhdr) == NULL) {
112 : 0 : ret = EPKG_WARN;
113 : 0 : pkg_debug(1, "getehdr() failed: %s.", elf_errmsg(-1));
114 : 0 : goto cleanup;
115 : : }
116 : :
117 [ + + + - : 25 : if (elfhdr.e_type != ET_DYN && elfhdr.e_type != ET_EXEC &&
# # ]
118 : 0 : elfhdr.e_type != ET_REL) {
119 : 0 : pkg_debug(1, "not an elf");
120 : 0 : ret = EPKG_END;
121 : 0 : goto cleanup;
122 : : }
123 : :
124 : : /* Parse the needed information from the dynamic section header */
125 : 25 : Elf_Scn *scn = NULL;
126 : 25 : Elf_Scn *dynamic = NULL;
127 : 25 : size_t numdyn = 0;
128 : 25 : size_t sh_link = 0;
129 [ - + ]: 507 : while ((scn = elf_nextscn(e, scn)) != NULL) {
130 : : GElf_Shdr shdr;
131 [ + - ]: 507 : if (gelf_getshdr(scn, &shdr) != &shdr) {
132 : 0 : ret = EPKG_FATAL;
133 : 0 : pkg_emit_error("getshdr() for %s failed: %s", fpath,
134 : 0 : elf_errmsg(-1));
135 : 0 : goto cleanup;
136 : : }
137 [ + + ]: 507 : if (shdr.sh_type == SHT_DYNAMIC) {
138 : 25 : dynamic = scn;
139 : 25 : sh_link = shdr.sh_link;
140 [ + - ]: 25 : if (shdr.sh_entsize == 0) {
141 : 0 : ret = EPKG_END;
142 : 0 : goto cleanup;
143 : : }
144 : 25 : numdyn = shdr.sh_size / shdr.sh_entsize;
145 : 25 : break;
146 : : }
147 : : }
148 : :
149 [ + - ]: 25 : if (dynamic == NULL) {
150 : 0 : ret = EPKG_END;
151 : 0 : goto cleanup; /* not a dynamically linked elf: no results */
152 : : }
153 : :
154 : : struct pkg_abi elf_abi;
155 : 25 : elf_parse_abi(e, &elfhdr, &elf_abi);
156 [ + - ]: 25 : if (elf_abi.arch == PKG_ARCH_UNKNOWN) {
157 : 0 : ret = EPKG_END;
158 : 0 : goto cleanup;
159 : : }
160 : :
161 [ + - ]: 25 : if (elf_abi.os == PKG_OS_UNKNOWN) {
162 : : /* There is no reliable way to identify shared libraries targeting Linux.
163 : : * It would be possible to reliably identify Linux executables by checking
164 : : * the dynamic linker path in DT_INTERP. Shared libraries however do not
165 : : * have DT_INTERP set.
166 : : *
167 : : * Reading the notes section for NT_GNU_ABI_TAG is not sufficient either
168 : : * as this is only required for executables, not shared libraries.
169 : : * See https://refspecs.linuxfoundation.org/LSB_1.2.0/gLSB/noteabitag.html
170 : : *
171 : : * Therefore, if pkg is targeting Linux assume that ELF files with unknown
172 : : * target OS are also targeting Linux.
173 : : *
174 : : * Furthermore, if pkg is targeting FreeBSD also assume that ELF
175 : : * files with unknown target OS are targeting Linux. This is consistent
176 : : * with the behavior of the FreeBSD kernel, which falls back to Linux by
177 : : * default if it is unable to determine the target OS of an ELF file.
178 : : * (This behavior can be overridden with a fallback_brand sysctl.)
179 : : *
180 : : * We could add a pkg option to configure the fallback OS
181 : : * in the future if necessary.
182 : : */
183 [ # # # # ]: 0 : if (ctx.abi.os == PKG_OS_LINUX || ctx.abi.os == PKG_OS_FREEBSD) {
184 : 0 : elf_abi.os = PKG_OS_LINUX;
185 : 0 : } else {
186 : 0 : ret = EPKG_END;
187 : 0 : goto cleanup;
188 : : }
189 : 0 : }
190 : :
191 : 25 : enum pkg_shlib_flags flags = pkg_shlib_flags_from_abi(&elf_abi);
192 [ + - + - ]: 25 : if ((flags & PKG_SHLIB_FLAGS_COMPAT_LINUX) == 0 && elf_abi.os != ctx.abi.os) {
193 : 0 : ret = EPKG_END;
194 : 0 : goto cleanup; /* Incompatible OS */
195 : : }
196 [ + - + - ]: 25 : if ((flags & PKG_SHLIB_FLAGS_COMPAT_32) == 0 && elf_abi.arch != ctx.abi.arch) {
197 : 0 : ret = EPKG_END;
198 : 0 : goto cleanup; /* Incompatible architecture */
199 : : }
200 : :
201 : 25 : Elf_Data *data = elf_getdata(dynamic, NULL);
202 [ + - ]: 25 : if (data == NULL) {
203 : 0 : ret = EPKG_END; /* Some error occurred, ignore this file */
204 : 0 : goto cleanup;
205 : : }
206 : :
207 [ + + ]: 638 : for (size_t dynidx = 0; dynidx < numdyn; dynidx++) {
208 : : GElf_Dyn *dyn, dyn_mem;
209 [ - + ]: 613 : if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
210 : 0 : ret = EPKG_FATAL;
211 : 0 : pkg_emit_error("getdyn() failed for %s: %s", fpath,
212 : 0 : elf_errmsg(-1));
213 : 0 : goto cleanup;
214 : : }
215 : :
216 : 613 : const char *shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);
217 [ + + + + ]: 613 : if (shlib == NULL || *shlib == '\0') {
218 : 393 : continue;
219 : : }
220 : :
221 : :
222 : :
223 [ + + ]: 220 : if (dyn->d_tag == DT_SONAME) {
224 : 10 : pkg_addshlib_provided(pkg, shlib, flags);
225 [ + + ]: 220 : } else if (dyn->d_tag == DT_NEEDED) {
226 : 32 : pkg_addshlib_required(pkg, shlib, flags);
227 : 32 : }
228 : 245 : }
229 : :
230 : : cleanup:
231 [ - + ]: 93 : if (e != NULL)
232 : 93 : elf_end(e);
233 : 93 : close(fd);
234 : :
235 : 93 : return (ret);
236 : 250 : }
237 : :
238 : : static int
239 : 0 : analyse_fpath(struct pkg *pkg, const char *fpath)
240 : : {
241 : : const char *dot;
242 : :
243 : 0 : dot = strrchr(fpath, '.');
244 : :
245 [ # # ]: 0 : if (dot == NULL) /* No extension */
246 : 0 : return (EPKG_OK);
247 : :
248 [ # # # # ]: 0 : if (dot[1] == 'a' && dot[2] == '\0')
249 : 0 : pkg->flags |= PKG_CONTAINS_STATIC_LIBS;
250 : :
251 [ # # # # : 0 : if ((dot[1] == 'l' && dot[2] == 'a' && dot[3] == '\0'))
# # ]
252 : 0 : pkg->flags |= PKG_CONTAINS_LA;
253 : :
254 : 0 : return (EPKG_OK);
255 : 0 : }
256 : :
257 : : static enum pkg_arch
258 : 8 : aeabi_parse_arm_attributes(void *data, size_t length)
259 : : {
260 : : uint32_t sect_len;
261 : 8 : uint8_t *section = data;
262 : :
263 : : #define MOVE(len) do { \
264 : : assert(length >= (len)); \
265 : : section += (len); \
266 : : length -= (len); \
267 : : } while (0)
268 : :
269 [ + - - + ]: 8 : if (length == 0 || *section != 'A')
270 : 0 : return (PKG_ARCH_UNKNOWN);
271 [ + - ]: 8 : MOVE(1);
272 : :
273 : : /* Read the section length */
274 [ - + ]: 8 : if (length < sizeof(sect_len))
275 : 0 : return (PKG_ARCH_UNKNOWN);
276 : 8 : memcpy(§_len, section, sizeof(sect_len));
277 : :
278 : : /*
279 : : * The section length should be no longer than the section it is within
280 : : */
281 [ - + ]: 8 : if (sect_len > length)
282 : 0 : return (PKG_ARCH_UNKNOWN);
283 : :
284 [ + - ]: 8 : MOVE(sizeof(sect_len));
285 : :
286 : : /* Skip the vendor name */
287 [ - + ]: 48 : while (length != 0) {
288 [ + + ]: 48 : if (*section == '\0')
289 : 8 : break;
290 [ - + ]: 40 : MOVE(1);
291 : : }
292 [ + - ]: 8 : if (length == 0)
293 : 0 : return (PKG_ARCH_UNKNOWN);
294 [ + - ]: 8 : MOVE(1);
295 : :
296 [ - + ]: 8 : while (length != 0) {
297 : : uint32_t tag_length;
298 : :
299 [ - - + - ]: 8 : switch(*section) {
300 : : case 1: /* Tag_File */
301 [ + - ]: 8 : MOVE(1);
302 [ - + ]: 8 : if (length < sizeof(tag_length))
303 : 0 : return (PKG_ARCH_UNKNOWN);
304 : 8 : memcpy(&tag_length, section, sizeof(tag_length));
305 : 8 : break;
306 : : case 2: /* Tag_Section */
307 : 0 : case 3: /* Tag_Symbol */
308 : : default:
309 : 0 : return (PKG_ARCH_UNKNOWN);
310 : : }
311 : : /* At least space for the tag and size */
312 [ - + ]: 8 : if (tag_length <= 5)
313 : 0 : return (PKG_ARCH_UNKNOWN);
314 : 8 : tag_length--;
315 : : /* Check the tag fits */
316 [ - + ]: 8 : if (tag_length > length)
317 : 0 : return (PKG_ARCH_UNKNOWN);
318 : :
319 : : #define MOVE_TAG(len) do { \
320 : : assert(tag_length >= (len)); \
321 : : MOVE(len); \
322 : : tag_length -= (len); \
323 : : } while(0)
324 : :
325 [ + - ]: 8 : MOVE(sizeof(tag_length));
326 : 8 : tag_length -= sizeof(tag_length);
327 : :
328 [ - + ]: 24 : while (tag_length != 0) {
329 : : uint8_t tag;
330 : :
331 [ + - ]: 24 : assert(tag_length >= length);
332 : :
333 : 24 : tag = *section;
334 [ - + + - ]: 24 : MOVE_TAG(1);
335 : :
336 : : /*
337 : : * These tag values come from:
338 : : *
339 : : * Addenda to, and Errata in, the ABI for the
340 : : * ARM Architecture. Release 2.08, section 2.3.
341 : : */
342 [ + + ]: 24 : if (tag == 6) { /* == Tag_CPU_arch */
343 : : uint8_t val;
344 : :
345 : 8 : val = *section;
346 : : /*
347 : : * We don't support values that require
348 : : * more than one byte.
349 : : */
350 [ - + ]: 8 : if (val & (1 << 7))
351 : 0 : return (PKG_ARCH_UNKNOWN);
352 : :
353 : : /* We have an ARMv4 or ARMv5 */
354 [ - + ]: 8 : if (val <= 5)
355 : 0 : return (PKG_ARCH_UNKNOWN);
356 [ + + ]: 8 : else if (val == 6) /* We have an ARMv6 */
357 : 4 : return (PKG_ARCH_ARMV6);
358 : : else /* We have an ARMv7+ */
359 : 4 : return (PKG_ARCH_ARMV7);
360 [ + - + + : 24 : } else if (tag == 4 || tag == 5 || tag == 32 ||
- + + - ]
361 [ - + ]: 8 : tag == 65 || tag == 67) {
362 [ + + - + : 132 : while (*section != '\0' && length != 0)
+ + ]
363 [ + - + - ]: 116 : MOVE_TAG(1);
364 [ + - ]: 16 : if (tag_length == 0)
365 : 0 : return (PKG_ARCH_UNKNOWN);
366 : : /* Skip the last byte */
367 [ + - + - ]: 16 : MOVE_TAG(1);
368 [ # # # # : 16 : } else if ((tag >= 7 && tag <= 31) || tag == 34 ||
# # # # ]
369 [ # # # # : 0 : tag == 36 || tag == 38 || tag == 42 || tag == 44 ||
# # # # ]
370 [ # # # # : 0 : tag == 64 || tag == 66 || tag == 68 || tag == 70) {
# # ]
371 : : /* Skip the uleb128 data */
372 [ # # # # : 0 : while (*section & (1 << 7) && length != 0)
# # ]
373 [ # # # # ]: 0 : MOVE_TAG(1);
374 [ # # ]: 0 : if (tag_length == 0)
375 : 0 : return (PKG_ARCH_UNKNOWN);
376 : : /* Skip the last byte */
377 [ # # # # ]: 0 : MOVE_TAG(1);
378 : 0 : } else
379 : 0 : return (PKG_ARCH_UNKNOWN);
380 : : #undef MOVE_TAG
381 : : }
382 : :
383 : 0 : break;
384 : : }
385 : 0 : return (PKG_ARCH_UNKNOWN);
386 : : #undef MOVE
387 : 8 : }
388 : :
389 : : static enum pkg_arch
390 : 913 : elf_parse_arch(Elf *elf, GElf_Ehdr *ehdr)
391 : : {
392 [ + + - + : 913 : switch (ehdr->e_machine) {
+ + + + ]
393 : : case EM_386:
394 : 4 : return (PKG_ARCH_I386);
395 : : case EM_X86_64:
396 : 881 : return (PKG_ARCH_AMD64);
397 : : case EM_AARCH64:
398 : 4 : return (PKG_ARCH_AARCH64);
399 : : case EM_ARM:
400 : : /* Only support EABI */
401 [ + - ]: 8 : if ((ehdr->e_flags & EF_ARM_EABIMASK) == 0) {
402 : 0 : return (PKG_ARCH_UNKNOWN);
403 : : }
404 : :
405 : : size_t shstrndx;
406 : 8 : elf_getshdrstrndx(elf, &shstrndx);
407 : :
408 : : GElf_Shdr shdr;
409 : 8 : Elf_Scn *scn = NULL;
410 [ - + ]: 208 : while ((scn = elf_nextscn(elf, scn)) != NULL) {
411 [ - + ]: 208 : if (gelf_getshdr(scn, &shdr) != &shdr) {
412 : 0 : break;
413 : : }
414 : 208 : const char *sh_name = elf_strptr(elf, shstrndx, shdr.sh_name);
415 [ - + ]: 208 : if (sh_name == NULL) {
416 : 0 : continue;
417 : : }
418 [ + + ]: 208 : if (STREQ(".ARM.attributes", sh_name)) {
419 : 8 : Elf_Data *data = elf_getdata(scn, NULL);
420 : 8 : return (aeabi_parse_arm_attributes(data->d_buf, data->d_size));
421 : : }
422 : : }
423 : 0 : break;
424 : : case EM_PPC:
425 : 4 : return (PKG_ARCH_POWERPC);
426 : : case EM_PPC64:
427 [ - + + ]: 8 : switch (ehdr->e_ident[EI_DATA]) {
428 : : case ELFDATA2MSB:
429 : 4 : return (PKG_ARCH_POWERPC64);
430 : : case ELFDATA2LSB:
431 : 4 : return (PKG_ARCH_POWERPC64LE);
432 : : }
433 : 0 : break;
434 : : case EM_RISCV:
435 [ - - + ]: 4 : switch (ehdr->e_ident[EI_CLASS]) {
436 : : case ELFCLASS32:
437 : 0 : return (PKG_ARCH_RISCV32);
438 : : case ELFCLASS64:
439 : 4 : return (PKG_ARCH_RISCV64);
440 : : }
441 : 0 : break;
442 : : }
443 : :
444 : 0 : return (PKG_ARCH_UNKNOWN);
445 : 913 : }
446 : :
447 : : /* Returns true if the OS and version were successfully parsed */
448 : : static bool
449 : 925 : elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct pkg_abi *abi)
450 : : {
451 : : Elf_Note note;
452 : : char *src;
453 : : uint32_t gnu_abi_tag[4];
454 : 925 : int note_ost[6] = {
455 : : PKG_OS_LINUX,
456 : : PKG_OS_UNKNOWN, /* GNU Hurd */
457 : : PKG_OS_UNKNOWN, /* Solaris */
458 : : PKG_OS_FREEBSD,
459 : : PKG_OS_NETBSD,
460 : : PKG_OS_UNKNOWN, /* Syllable */
461 : : };
462 : 925 : uint32_t version = 0;
463 : 925 : int version_style = 1;
464 : :
465 : 925 : src = data->d_buf;
466 : :
467 [ + + ]: 961 : while ((uintptr_t)src < ((uintptr_t)data->d_buf + data->d_size)) {
468 : 949 : memcpy(¬e, src, sizeof(Elf_Note));
469 : 949 : src += sizeof(Elf_Note);
470 [ + + - + ]: 965 : if ((strncmp ((const char *) src, "FreeBSD", note.n_namesz) == 0) ||
471 [ + + ]: 20 : (strncmp ((const char *) src, "DragonFly", note.n_namesz) == 0) ||
472 [ + - ]: 16 : (strncmp ((const char *) src, "NetBSD", note.n_namesz) == 0) ||
473 : 16 : (note.n_namesz == 0)) {
474 [ + + ]: 933 : if (note.n_type == NT_VERSION) {
475 : 909 : version_style = 1;
476 : 909 : break;
477 : : }
478 : 24 : }
479 [ + + ]: 40 : if (strncmp ((const char *) src, "GNU", note.n_namesz) == 0) {
480 [ + + ]: 16 : if (note.n_type == NT_GNU_ABI_TAG) {
481 : 4 : version_style = 2;
482 : 4 : break;
483 : : }
484 : 12 : }
485 : 36 : src += roundup2(note.n_namesz + note.n_descsz, 4);
486 : : }
487 [ + + ]: 925 : if ((uintptr_t)src >= ((uintptr_t)data->d_buf + data->d_size)) {
488 : 12 : return (false);
489 : : }
490 [ + + ]: 913 : if (version_style == 2) {
491 : : /*
492 : : * NT_GNU_ABI_TAG
493 : : * Operating system (OS) ABI information. The
494 : : * desc field contains 4 words:
495 : : * word 0: OS descriptor (ELF_NOTE_OS_LINUX, ELF_NOTE_OS_GNU, etc)
496 : : * word 1: major version of the ABI
497 : : * word 2: minor version of the ABI
498 : : * word 3: subminor version of the ABI
499 : : */
500 : 4 : src += roundup2(note.n_namesz, 4);
501 [ - + ]: 4 : if (elfhdr->e_ident[EI_DATA] == ELFDATA2MSB) {
502 [ # # ]: 0 : for (int wdndx = 0; wdndx < 4; wdndx++) {
503 : 0 : gnu_abi_tag[wdndx] = be32dec(src);
504 : 0 : src += 4;
505 : 0 : }
506 : 0 : } else {
507 [ + + ]: 20 : for (int wdndx = 0; wdndx < 4; wdndx++) {
508 : 16 : gnu_abi_tag[wdndx] = le32dec(src);
509 : 16 : src += 4;
510 : 16 : }
511 : : }
512 [ + - ]: 4 : if (gnu_abi_tag[0] < 6) {
513 : 4 : abi->os= note_ost[gnu_abi_tag[0]];
514 : 4 : } else {
515 : 0 : abi->os = PKG_OS_UNKNOWN;
516 : : }
517 : 4 : } else {
518 [ + - ]: 909 : if (note.n_namesz == 0) {
519 : 0 : abi->os = PKG_OS_UNKNOWN;
520 : 0 : } else {
521 [ + + ]: 909 : if (STREQ(src, "FreeBSD"))
522 : 905 : abi->os = PKG_OS_FREEBSD;
523 [ - + ]: 4 : else if (STREQ(src, "DragonFly"))
524 : 4 : abi->os = PKG_OS_DRAGONFLY;
525 [ # # ]: 0 : else if (STREQ(src, "NetBSD"))
526 : 0 : abi->os = PKG_OS_NETBSD;
527 : : }
528 : 909 : src += roundup2(note.n_namesz, 4);
529 [ + + ]: 909 : if (elfhdr->e_ident[EI_DATA] == ELFDATA2MSB)
530 : 8 : version = be32dec(src);
531 : : else
532 : 901 : version = le32dec(src);
533 : : }
534 : :
535 [ + + ]: 913 : if (version_style == 2) {
536 [ + - ]: 4 : if (abi->os == PKG_OS_LINUX) {
537 : 4 : abi->major = gnu_abi_tag[1];
538 : 4 : abi->minor = gnu_abi_tag[2];
539 : 4 : } else {
540 : 0 : abi->major = gnu_abi_tag[1];
541 : 0 : abi->minor = gnu_abi_tag[2];
542 : 0 : abi->patch = gnu_abi_tag[3];
543 : : }
544 : 4 : } else {
545 [ - + - + : 909 : switch (abi->os) {
- ]
546 : : case PKG_OS_UNKNOWN:
547 : 0 : break;
548 : : case PKG_OS_FREEBSD:
549 : 905 : pkg_abi_set_freebsd_osversion(abi, version);
550 : 905 : break;
551 : : case PKG_OS_DRAGONFLY:
552 : 4 : abi->major = version / 100000;
553 : 4 : abi->minor = (((version / 100 % 1000)+1)/2)*2;
554 : 4 : break;
555 : : case PKG_OS_NETBSD:
556 : 0 : abi->major = (version + 1000000) / 100000000;
557 : 0 : break;
558 : : default:
559 : 0 : assert(0);
560 : : }
561 : : }
562 : :
563 : 913 : return (true);
564 : 925 : }
565 : :
566 : : static void
567 : 913 : elf_parse_abi(Elf *elf, GElf_Ehdr *ehdr, struct pkg_abi *abi)
568 : : {
569 : 913 : *abi = (struct pkg_abi){0};
570 : :
571 : 913 : Elf_Scn *scn = NULL;
572 [ + + ]: 28345 : while ((scn = elf_nextscn(elf, scn)) != NULL) {
573 : : GElf_Shdr shdr;
574 [ - + ]: 27432 : if (gelf_getshdr(scn, &shdr) != &shdr) {
575 : 0 : pkg_emit_error("getshdr() failed: %s.", elf_errmsg(-1));
576 : 0 : return;
577 : : }
578 : :
579 [ + + ]: 27432 : if (shdr.sh_type == SHT_NOTE) {
580 : 925 : Elf_Data *data = elf_getdata(scn, NULL);
581 : : /*
582 : : * loop over all the note section and override what
583 : : * should be overridden if any
584 : : */
585 : 925 : elf_note_analyse(data, ehdr, abi);
586 : 925 : }
587 : : }
588 : :
589 : 913 : abi->arch = elf_parse_arch(elf, ehdr);
590 : 913 : }
591 : :
592 : : int
593 : 925 : pkg_elf_abi_from_fd(int fd, struct pkg_abi *abi)
594 : : {
595 : 925 : Elf *elf = NULL;
596 : : GElf_Ehdr elfhdr;
597 : 925 : int ret = EPKG_OK;
598 : :
599 [ + - ]: 925 : if (elf_version(EV_CURRENT) == EV_NONE) {
600 : 0 : pkg_emit_error("ELF library initialization failed: %s",
601 : 0 : elf_errmsg(-1));
602 : 0 : return (EPKG_FATAL);
603 : : }
604 : :
605 [ + - ]: 925 : if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
606 : 0 : ret = EPKG_FATAL;
607 : 0 : pkg_emit_error("elf_begin() failed: %s.", elf_errmsg(-1));
608 : 0 : goto cleanup;
609 : : }
610 : :
611 [ + + ]: 925 : if (gelf_getehdr(elf, &elfhdr) == NULL) {
612 : 37 : ret = EPKG_WARN;
613 : 37 : pkg_debug(1, "getehdr() failed: %s.", elf_errmsg(-1));
614 : 37 : goto cleanup;
615 : : }
616 : :
617 : 888 : elf_parse_abi(elf, &elfhdr, abi);
618 : :
619 [ + - ]: 888 : if (abi->os == PKG_OS_UNKNOWN) {
620 : 0 : ret = EPKG_FATAL;
621 : 0 : pkg_emit_error("failed to determine the operating system");
622 : 0 : goto cleanup;
623 : : }
624 : :
625 [ + - ]: 888 : if (abi->arch == PKG_ARCH_UNKNOWN) {
626 : 0 : ret = EPKG_FATAL;
627 : 0 : pkg_emit_error("failed to determine the architecture");
628 : 0 : goto cleanup;
629 : : }
630 : :
631 : : cleanup:
632 [ - + ]: 925 : if (elf != NULL)
633 : 925 : elf_end(elf);
634 : 925 : return (ret);
635 : 925 : }
636 : :
637 : 323 : int pkg_analyse_init_elf(__unused const char* stage) {
638 [ + - ]: 323 : if (elf_version(EV_CURRENT) == EV_NONE)
639 : 0 : return (EPKG_FATAL);
640 : 323 : return (EPKG_OK);
641 : 323 : }
642 : :
643 : 250 : int pkg_analyse_elf(const bool developer_mode, struct pkg *pkg, const char *fpath)
644 : : {
645 : 250 : int ret = analyse_elf(pkg, fpath);
646 [ + - ]: 250 : if (developer_mode) {
647 [ # # # # ]: 0 : if (ret != EPKG_OK && ret != EPKG_END) {
648 : 0 : return EPKG_WARN;
649 : : }
650 : 0 : analyse_fpath(pkg, fpath);
651 : 0 : }
652 : 250 : return ret;
653 : 250 : }
654 : :
655 : 323 : int pkg_analyse_close_elf() {
656 : 323 : return EPKG_OK;
657 : : }
|