]> git.ipfire.org Git - pakfire.git/blob - src/pakfire/elf.c
6c97b18c32beaa58e281f14ae140ae67ab6f1261
[pakfire.git] / src / pakfire / elf.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2025 Pakfire development team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <errno.h>
22 #include <stdlib.h>
23
24 #include <pakfire/ctx.h>
25 #include <pakfire/elf.h>
26 #include <pakfire/file.h>
27 #include <pakfire/hex.h>
28 #include <pakfire/logging.h>
29 #include <pakfire/path.h>
30 #include <pakfire/string.h>
31
32 // libelf
33 #include <gelf.h>
34 #include <elfutils/libdwelf.h>
35
36 struct pakfire_elf {
37 struct pakfire_ctx* ctx;
38 int nrefs;
39
40 // Path
41 char path[PATH_MAX];
42
43 // File Descriptor
44 int fd;
45
46 // ELF Object
47 Elf* elf;
48
49 // ELF Header
50 GElf_Ehdr ehdr;
51
52 // Number of Program Headers
53 size_t phnum;
54
55 // Strings
56 size_t shstrndx;
57
58 // Interpreter
59 const char* interpreter;
60
61 // SONAME
62 const char* soname;
63
64 // GNU Build ID
65 char* build_id;
66
67 // GNU Debuglink
68 const char* debuglink;
69 };
70
71 static int pakfire_elf_init_libelf(struct pakfire_ctx* ctx) {
72 // Initialize libelf
73 if (elf_version(EV_CURRENT) == EV_NONE) {
74 ERROR(ctx, "Could not initialize libelf: %s\n", elf_errmsg(-1));
75 return -EINVAL;
76 }
77
78 return 0;
79 }
80
81 static int pakfire_elf_open_elf(struct pakfire_elf* self) {
82 GElf_Ehdr* ehdr = NULL;
83 int r;
84
85 // Make sure libelf is initialized
86 r = pakfire_elf_init_libelf(self->ctx);
87 if (r < 0)
88 return r;
89
90 // Open the ELF file
91 self->elf = elf_begin(self->fd, ELF_C_READ, NULL);
92 if (!self->elf) {
93 ERROR(self->ctx, "Could not open ELF file: %m\n");
94 return -errno;
95 }
96
97 // Is this actually an ELF file?
98 switch (elf_kind(self->elf)) {
99 case ELF_K_ELF:
100 break;
101
102 // Fail for everything else
103 default:
104 return -ENOTSUP;
105 }
106
107 // Fetch the ELF header
108 ehdr = gelf_getehdr(self->elf, &self->ehdr);
109 if (!ehdr) {
110 ERROR(self->ctx, "Could not fetch the ELF header: %s\n", elf_errmsg(-1));
111 return -EINVAL;
112 }
113
114 // Fetch the total numbers of program headers
115 r = elf_getphdrnum(self->elf, &self->phnum);
116 if (r) {
117 ERROR(self->ctx,
118 "Could not fetch number of program headers: %s\n", elf_errmsg(-1));
119 return -EINVAL;
120 }
121
122 // Find the strings
123 r = elf_getshdrstrndx(self->elf, &self->shstrndx);
124 if (r < 0) {
125 ERROR(self->ctx, "elf_getshdrstrndx() failed: %s\n", elf_errmsg(-1));
126 return -EINVAL;
127 }
128
129 return 0;
130 }
131
132 static void pakfire_elf_free(struct pakfire_elf* self) {
133 if (self->build_id)
134 free(self->build_id);
135 if (self->elf)
136 elf_end(self->elf);
137 if (self->fd >= 0)
138 close(self->fd);
139 if (self->ctx)
140 pakfire_ctx_unref(self->ctx);
141 free(self);
142 }
143
144 int pakfire_elf_open(struct pakfire_elf** elf,
145 struct pakfire_ctx* ctx, const char* path, int fd) {
146 struct pakfire_elf* self = NULL;
147 int r;
148
149 // Require a valid file descriptor
150 if (fd < 0)
151 return -EBADF;
152
153 // Allocate a new object
154 self = calloc(1, sizeof(*self));
155 if (!self)
156 return -errno;
157
158 // Store a reference to the context
159 self->ctx = pakfire_ctx_ref(ctx);
160
161 // Initialize the reference counter
162 self->nrefs = 1;
163
164 // Store the path
165 r = pakfire_string_set(self->path, path);
166 if (r < 0)
167 goto ERROR;
168
169 // Store the file descriptor
170 self->fd = dup(fd);
171 if (self->fd < 0) {
172 ERROR(self->ctx, "Could not duplicate file descriptor: %m\n");
173 r = -errno;
174 goto ERROR;
175 }
176
177 // Open the ELF file
178 r = pakfire_elf_open_elf(self);
179 if (r < 0)
180 goto ERROR;
181
182 // Return the pointer
183 *elf = self;
184
185 return 0;
186
187 ERROR:
188 pakfire_elf_free(self);
189
190 return r;
191 }
192
193 int pakfire_elf_open_file(struct pakfire_elf** elf,
194 struct pakfire_ctx* ctx, struct pakfire_file* file) {
195 const char* path = NULL;
196 int fd = -EBADF;
197 int r;
198
199 // Fetch the path
200 path = pakfire_file_get_path(file);
201
202 // Open the file
203 fd = pakfire_file_open(file, 0);
204 if (fd < 0)
205 return -errno;
206
207 // Open the ELF object
208 r = pakfire_elf_open(elf, ctx, path, fd);
209 if (r < 0)
210 goto ERROR;
211
212 ERROR:
213 if (fd >= 0)
214 close(fd);
215
216 return r;
217 }
218
219 struct pakfire_elf* pakfire_elf_ref(struct pakfire_elf* self) {
220 self->nrefs++;
221
222 return self;
223 }
224
225 struct pakfire_elf* pakfire_elf_unref(struct pakfire_elf* self) {
226 if (--self->nrefs > 0)
227 return self;
228
229 pakfire_elf_free(self);
230 return NULL;
231 }
232
233 const char* pakfire_elf_path(struct pakfire_elf* self) {
234 return self->path;
235 }
236
237 int pakfire_elf_type(struct pakfire_elf* self) {
238 return self->ehdr.e_type;
239 }
240
241 int pakfire_elf_machine(struct pakfire_elf* self) {
242 return self->ehdr.e_machine;
243 }
244
245 int pakfire_elf_is_elf64(struct pakfire_elf* self) {
246 return self->ehdr.e_ident[EI_CLASS] = ELFCLASS64;
247 }
248
249 int pakfire_elf_endianess(struct pakfire_elf* self) {
250 return self->ehdr.e_ident[EI_DATA];
251 }
252
253 const char* pakfire_elf_build_id(struct pakfire_elf* self) {
254 const void* buffer = NULL;
255 ssize_t length;
256
257 if (!self->build_id) {
258 // Extract the GNU Build ID
259 length = dwelf_elf_gnu_build_id(self->elf, &buffer);
260 if (length < 0) {
261 ERROR(self->ctx, "Could not read the GNU Build ID from %s: %s\n",
262 self->path, elf_errmsg(-1));
263 return NULL;
264 }
265
266 // Return NULL if there is no Build ID
267 if (!length)
268 return NULL;
269
270 // Convert the Build ID to hex
271 self->build_id = __pakfire_hexlify(buffer, length);
272 if (!self->build_id) {
273 ERROR(self->ctx, "Could not convert the Build ID into hex format: %m\n");
274 return NULL;
275 }
276
277 DEBUG(self->ctx, "%s has Build ID %s\n", self->path, self->build_id);
278 }
279
280 return self->build_id;
281 }
282
283 const char* pakfire_elf_debuglink(struct pakfire_elf* self) {
284 GElf_Word crc32;
285
286 // Fetch the debug link
287 if (!self->debuglink) {
288 self->debuglink = dwelf_elf_gnu_debuglink(self->elf, &crc32);
289 if (!self->debuglink)
290 return NULL;
291
292 DEBUG(self->ctx, "%s has debug link pointing at %s\n",
293 self->path, self->debuglink);
294 }
295
296 return self->debuglink;
297 }
298
299 typedef int (*pakfire_elf_foreach_program_header_callback)
300 (struct pakfire_elf* self, const GElf_Phdr* phdr, void* data);
301
302 static int pakfire_elf_foreach_program_header(struct pakfire_elf* self,
303 pakfire_elf_foreach_program_header_callback callback, void* data) {
304 GElf_Phdr phdr = {};
305 int r = 0;
306
307 // Walk through all program headers
308 for (unsigned int i = 0; i < self->phnum; i++) {
309 if (!gelf_getphdr(self->elf, i, &phdr)) {
310 ERROR(self->ctx, "Could not parse program header: %s\n", elf_errmsg(-1));
311 return -ENOTSUP;
312 }
313
314 // Call the callback
315 r = callback(self, &phdr, data);
316 if (r)
317 break;
318 }
319
320 return r;
321 }
322
323 static int pakfire_elf_get_section(struct pakfire_elf* self,
324 const Elf64_Word type, const char* name, Elf_Scn** section, GElf_Shdr* header, Elf_Data** data) {
325 const char* sname = NULL;
326 Elf_Scn* s = NULL;
327 GElf_Shdr shdr;
328
329 // Walk through all sections
330 for (;;) {
331 s = elf_nextscn(self->elf, s);
332 if (!s)
333 break;
334
335 // Fetch the section header
336 gelf_getshdr(s, &shdr);
337
338 // Return any matching sections
339 if (shdr.sh_type == type) {
340 // If we have a name, check it too
341 if (name) {
342 sname = elf_strptr(self->elf, self->shstrndx, shdr.sh_name);
343 if (!sname)
344 continue;
345
346 // Skip if the name does not match
347 if (!pakfire_string_equals(name, sname))
348 continue;
349 }
350
351 // Return a pointer to the section
352 *section = s;
353
354 // Send header if requested
355 if (header)
356 gelf_getshdr(s, header);
357
358 // Send data if requested
359 if (data)
360 *data = elf_getdata(s, NULL);
361
362 return 0;
363 }
364 }
365
366 // No section found
367 return 1;
368 }
369
370 typedef int (*pakfire_elf_foreach_section_callback)(struct pakfire_elf* self,
371 Elf_Scn* section, const GElf_Shdr* shdr, void* data);
372
373 static int pakfire_elf_foreach_section(struct pakfire_elf* self,
374 const Elf64_Word type, pakfire_elf_foreach_section_callback callback, void* data) {
375 Elf_Scn* section = NULL;
376 GElf_Shdr shdr = {};
377 int r;
378
379 // Walk through all sections
380 for (;;) {
381 section = elf_nextscn(self->elf, section);
382 if (!section)
383 break;
384
385 // Fetch the section header
386 if (!gelf_getshdr(section, &shdr)) {
387 ERROR(self->ctx, "%s: Could not fetch the ELF section header: %s\n",
388 self->path, elf_errmsg(-1));
389 return -EINVAL;
390 }
391
392 // Skip sections that don't match
393 if (type && shdr.sh_type != type)
394 continue;
395
396 // Call the callback
397 r = callback(self, section, &shdr, data);
398 if (r)
399 return r;
400 }
401
402 return 0;
403 }
404
405 typedef int (*pakfire_elf_dyn_walk_callback)
406 (struct pakfire_elf* self, const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data);
407
408 static int pakfire_elf_dyn_walk(struct pakfire_elf* self,
409 pakfire_elf_dyn_walk_callback callback, void* data) {
410 Elf_Scn* dynamic = NULL;
411 GElf_Shdr shdr;
412 Elf_Data* elf_data = NULL;
413 GElf_Dyn dyn;
414 int r;
415
416 // Find the dynamic linking information
417 r = pakfire_elf_get_section(self, SHT_DYNAMIC, NULL, &dynamic, &shdr, &elf_data);
418 if (r) {
419 DEBUG(self->ctx, "%s does not have a dynamic section\n", self->path);
420 return r;
421 }
422
423 // Walk through all entries...
424 for (unsigned int i = 0; ; i++) {
425 // Fetch the next entry
426 if (!gelf_getdyn(elf_data, i, &dyn))
427 break;
428
429 // Call the callback
430 r = callback(self, &shdr, &dyn, data);
431 if (r)
432 return r;
433 }
434
435 return 0;
436 }
437
438 static int pakfire_elf_fetch_interpreter(
439 struct pakfire_elf* self, const GElf_Phdr* phdr, void* data) {
440 Elf_Data* chunk = NULL;
441
442 switch (phdr->p_type) {
443 case PT_INTERP:
444 chunk = elf_getdata_rawchunk(self->elf, phdr->p_offset, phdr->p_filesz, ELF_T_BYTE);
445 if (!chunk || !chunk->d_buf) {
446 ERROR(self->ctx, "Failed to fetch the interpreter\n");
447 return -EINVAL;
448 }
449
450 // Store the interpreter
451 self->interpreter = (const char*)chunk->d_buf;
452 break;
453
454 default:
455 break;
456 }
457
458 return 0;
459 }
460
461 const char* pakfire_elf_interpreter(struct pakfire_elf* self) {
462 int r;
463
464 // Fetch the interpreter if not available
465 if (!self->interpreter) {
466 r = pakfire_elf_foreach_program_header(self, pakfire_elf_fetch_interpreter, NULL);
467 if (r < 0)
468 return NULL;
469 }
470
471 return self->interpreter;
472 }
473
474 static int pakfire_elf_fetch_soname(struct pakfire_elf* self,
475 const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
476 switch (dyn->d_tag) {
477 case DT_SONAME:
478 self->soname = elf_strptr(self->elf, shdr->sh_link, dyn->d_un.d_val);
479
480 return 1;
481 }
482
483 return 0;
484 }
485
486 const char* pakfire_elf_soname(struct pakfire_elf* self) {
487 int r;
488
489 // Fetch the SONAME if not available
490 if (!self->soname) {
491 r = pakfire_elf_dyn_walk(self, pakfire_elf_fetch_soname, NULL);
492 if (r < 0)
493 return NULL;
494 }
495
496 return self->soname;
497 }
498
499 int pakfire_elf_is_pie(struct pakfire_elf* self) {
500 switch (pakfire_elf_type(self)) {
501 // Shared Object files are good
502 case ET_DYN:
503 return 1;
504
505 // Everything else is bad
506 default:
507 break;
508 }
509
510 return 0;
511 }
512
513 int pakfire_elf_has_ssp(struct pakfire_elf* self) {
514 GElf_Sym symbol = {};
515 int r;
516
517 // .dynsym
518 Elf_Scn* dynsym = NULL;
519 GElf_Shdr symhdr = {};
520 Elf_Data* symdata = NULL;
521
522 // .dynstr
523 Elf_Scn* dynstr = NULL;
524 GElf_Shdr strhdr = {};
525 Elf_Data* strdata = NULL;
526
527 // Fetch .dynsym
528 r = pakfire_elf_get_section(self, SHT_DYNSYM, NULL, &dynsym, &symhdr, &symdata);
529 if (r) {
530 DEBUG(self->ctx, "%s has no .dynsym section\n", self->path);
531 return 0;
532 }
533
534 // Fetch .dynstr
535 r = pakfire_elf_get_section(self, SHT_STRTAB, ".dynstr", &dynstr, &strhdr, &strdata);
536 if (r) {
537 DEBUG(self->ctx, "%s has no .dynstr section\n", self->path);
538 return 0;
539 }
540
541 // Count any global functions
542 size_t counter = 0;
543
544 // Walk through all symbols
545 for (unsigned int i = 0; i < symhdr.sh_size / symhdr.sh_entsize; i++) {
546 gelf_getsym(symdata, i, &symbol);
547
548 // Fetch the symbol name
549 const char* name = elf_strptr(self->elf, elf_ndxscn(dynstr), symbol.st_name);
550
551 // Skip empty section names
552 if (!name || !*name)
553 continue;
554
555 // Exit if there is a symbol called "__stack_chk_fail"
556 if (pakfire_string_startswith(name, "__stack_chk_fail"))
557 return 1;
558
559 // Or if the symbol is called __stack_chk_guard
560 else if (pakfire_string_startswith(name, "__stack_chk_guard"))
561 return 1;
562
563 // Or if the symbol is called __intel_security_cookie
564 else if (pakfire_string_startswith(name, "__intel_security_cookie"))
565 return 1;
566
567 // Count any global functions
568 if ((ELF64_ST_BIND(symbol.st_info) == STB_GLOBAL) &&
569 (ELF64_ST_TYPE(symbol.st_info) == STT_FUNC))
570 counter++;
571 }
572
573 // If we have something that does not have an exported function, we just assume yes
574 if (!counter) {
575 DEBUG(self->ctx, "%s has no functions. Skipping SSP check.\n", self->path);
576 return 1;
577 }
578
579 return 0;
580 }
581
582 static int pakfire_elf_check_execstack(
583 struct pakfire_elf* self, const GElf_Phdr* phdr, void* data) {
584 switch (phdr->p_type) {
585 case PT_GNU_STACK:
586 DEBUG(self->ctx,
587 "%s: GNU_STACK flags: %c%c%c\n",
588 self->path,
589 (phdr->p_flags & PF_R) ? 'R' : '-',
590 (phdr->p_flags & PF_W) ? 'W' : '-',
591 (phdr->p_flags & PF_X) ? 'X' : '-'
592 );
593
594 // The stack cannot be writable and executable
595 if ((phdr->p_flags & PF_W) && (phdr->p_flags & PF_X))
596 return 1;
597
598 default:
599 break;
600 }
601
602 return 0;
603 }
604
605 int pakfire_elf_has_execstack(struct pakfire_elf* self) {
606 return pakfire_elf_foreach_program_header(self, pakfire_elf_check_execstack, NULL);
607 }
608
609 static int pakfire_elf_has_bind_now(struct pakfire_elf* self,
610 const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
611 switch (dyn->d_tag) {
612 case DT_BIND_NOW:
613 return 1;
614 break;
615
616 case DT_FLAGS:
617 if (dyn->d_un.d_val & DF_BIND_NOW)
618 return 1;
619 break;
620
621 case DT_FLAGS_1:
622 if (dyn->d_un.d_val & DF_1_NOW)
623 return 1;
624 break;
625
626 default:
627 break;
628 }
629
630 return 0;
631 }
632
633 int pakfire_elf_is_fully_relro(struct pakfire_elf* self) {
634 return pakfire_elf_dyn_walk(self, pakfire_elf_has_bind_now, NULL);
635 }
636
637 int pakfire_elf_is_partially_relro(struct pakfire_elf* self) {
638 GElf_Phdr phdr;
639
640 // Walk through all program headers
641 for (unsigned int i = 0;; i++) {
642 if (!gelf_getphdr(self->elf, i, &phdr))
643 break;
644
645 switch (phdr.p_type) {
646 case PT_GNU_RELRO:
647 return 1;
648
649 default:
650 break;
651 }
652 }
653
654 return 0;
655 }
656
657 static uint32_t read_4_bytes(const int endianess, const char* data) {
658 uint32_t bytes = 0;
659
660 switch (endianess) {
661 // Litte Endian
662 case ELFDATA2LSB:
663 bytes = data[0] |
664 ((uint32_t)data[1] << 8) |
665 ((uint32_t)data[2] << 16) |
666 ((uint32_t)data[3] << 24);
667 break;
668
669 // Big endian
670 case ELFDATA2MSB:
671 bytes = data[3] |
672 ((uint32_t)data[2] << 8) |
673 ((uint32_t)data[1] << 16) |
674 ((uint32_t)data[0] << 24);
675 break;
676 }
677
678 return bytes;
679 }
680
681 static int pakfire_elf_check_cf_protection_aarch64(struct pakfire_elf* self,
682 const int endianess, const uint32_t type, const char* payload) {
683 int flags = 0;
684
685 switch (type) {
686 case GNU_PROPERTY_AARCH64_FEATURE_1_AND:
687 break;
688
689 // Ignore the rest
690 default:
691 return 0;
692 }
693
694 uint32_t property = read_4_bytes(endianess, payload);
695
696 // Check for BTI
697 if (!(property & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
698 flags |= PAKFIRE_ELF_MISSING_BTI;
699
700 // Check for PAC
701 if (!(property & GNU_PROPERTY_AARCH64_FEATURE_1_PAC))
702 flags |= PAKFIRE_ELF_MISSING_PAC;
703
704 return flags;
705 }
706
707 static int pakfire_elf_check_cf_protection_riscv64(struct pakfire_elf* self,
708 const int endianess, const uint32_t type, const char* payload) {
709 // There is nothing to do here
710 return 0;
711 }
712
713 static int pakfire_elf_check_cf_protection_x86_64(struct pakfire_elf* self,
714 const int endianess, const uint32_t type, const char* payload) {
715 int flags = 0;
716
717 switch (type) {
718 case GNU_PROPERTY_X86_FEATURE_1_AND:
719 break;
720
721 // Ignore the rest
722 default:
723 return 0;
724 }
725
726 uint32_t property = read_4_bytes(endianess, payload);
727
728 // Check for IBT
729 if (!(property & GNU_PROPERTY_X86_FEATURE_1_IBT))
730 flags |= PAKFIRE_ELF_MISSING_IBT;
731
732 // Check for Shadow Stack
733 if (!(property & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
734 flags |= PAKFIRE_ELF_MISSING_SHSTK;
735
736 return flags;
737 }
738
739 static int pakfire_elf_check_cf_protection(struct pakfire_elf* self,
740 Elf_Scn* section, const GElf_Shdr* shdr, void* data) {
741 GElf_Nhdr nhdr = {};
742 size_t offset = 0;
743 size_t offset_name = 0;
744 size_t offset_data = 0;
745 int r;
746
747 // Fetch data
748 Elf_Data* d = elf_getdata(section, NULL);
749
750 // Fetch the .note header
751 offset = gelf_getnote(d, offset, &nhdr, &offset_name, &offset_data);
752 if (!offset) {
753 ERROR(self->ctx, "%s: Could not read note section: %s\n",
754 self->path, elf_errmsg(-1));
755 return -errno;
756 }
757
758 // Skip any other note headers
759 switch (nhdr.n_type) {
760 case NT_GNU_PROPERTY_TYPE_0:
761 break;
762
763 // We are not interested in this here
764 default:
765 return 0;
766 }
767
768 #if 0
769 // Check if the name starts with "GNU"
770 if (nhdr.n_namesz == sizeof(ELF_NOTE_GNU) {
771 if (strcmp(data->d_buf + offset_name, ELF_NOTE_GNU) == 0)
772 break;
773 }
774 #endif
775
776 size_t length = nhdr.n_descsz;
777
778 // XXX Check if this is aligned to 8 bytes or 4 bytes on 32 bit
779
780 // Fetch the endianess
781 const int endianess = pakfire_elf_endianess(self);
782
783 const char* payload = (const char*)d->d_buf + offset_data;
784
785 while (length) {
786 // Read the type and size of the .note section
787 const uint32_t type = read_4_bytes(endianess, payload);
788 const uint32_t size = read_4_bytes(endianess, payload + 4);
789
790 // Skip header
791 length -= sizeof(type) + sizeof(size);
792 payload += sizeof(type) + sizeof(size);
793
794 if (length < size) {
795 ERROR(self->ctx, "GNU Property note has an incorrect format\n");
796 return -EINVAL;
797 }
798
799 switch (pakfire_elf_machine(self)) {
800 case EM_AARCH64:
801 r = pakfire_elf_check_cf_protection_aarch64(self, endianess, type, payload);
802 if (r < 0)
803 return r;
804 break;
805
806 case EM_RISCV:
807 r = pakfire_elf_check_cf_protection_riscv64(self, endianess, type, payload);
808 if (r < 0)
809 return r;
810 break;
811
812 case EM_X86_64:
813 r = pakfire_elf_check_cf_protection_x86_64(self, endianess, type, payload);
814 if (r < 0)
815 return r;
816 break;
817
818 default:
819 ERROR(self->ctx, "Unsupported ELF type (%d)\n", pakfire_elf_machine(self));
820 return -ENOTSUP;
821 }
822
823 // Skip data part
824 length -= (size + 7) & ~7;
825 payload += (size + 7) & ~7;
826 }
827
828 return 0;
829 }
830
831 int pakfire_elf_has_cf_protection(struct pakfire_elf* self) {
832 return pakfire_elf_foreach_section(self, SHT_NOTE, pakfire_elf_check_cf_protection, NULL);
833 }
834
835 static int pakfire_elf_check_runpath(struct pakfire_elf* self,
836 const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
837 const char* runpath = NULL;
838 const char* value = NULL;
839 char buffer[PATH_MAX];
840 char* p = NULL;
841 int r;
842
843 // The result
844 char*** runpaths = data;
845
846 switch (dyn->d_tag) {
847 case DT_RUNPATH:
848 case DT_RPATH:
849 // Fetch the value
850 value = elf_strptr(self->elf, shdr->sh_link, dyn->d_un.d_val);
851 if (!value)
852 return 1;
853
854 DEBUG(self->ctx, "%s has a RUNPATH: %s\n", self->path, value);
855
856 // Copy the value into a buffer we can modify
857 r = pakfire_string_set(buffer, value);
858 if (r < 0)
859 goto ERROR;
860
861 // Split the value by :
862 runpath = strtok_r(buffer, ":", &p);
863
864 // Iterate over all elements
865 while (runpath) {
866 r = pakfire_strings_append(runpaths, runpath);
867 if (r < 0)
868 goto ERROR;
869
870 // Move on to the next RUNPATH
871 runpath = strtok_r(NULL, ":", &p);
872 }
873
874 default:
875 break;
876 }
877
878 return 0;
879
880 ERROR:
881 if (*runpaths) {
882 pakfire_strings_free(*runpaths);
883 *runpaths = NULL;
884 }
885
886 return r;
887 }
888
889 int pakfire_elf_has_runpaths(struct pakfire_elf* self, char*** runpaths) {
890 return pakfire_elf_dyn_walk(self, pakfire_elf_check_runpath, runpaths);
891 }
892
893 static int __pakfire_elf_is_stripped(struct pakfire_elf* self,
894 Elf_Scn* section, const Elf64_Shdr* shdr, void* data) {
895 // Fetch the section name
896 const char* name = elf_strptr(self->elf, self->shstrndx, shdr->sh_name);
897 if (!name)
898 return -EINVAL;
899
900 switch (shdr->sh_type) {
901 // We should not have .symtab
902 case SHT_SYMTAB:
903 return 1;
904
905 // We should not have .symstr
906 case SHT_STRTAB:
907 if (pakfire_string_equals(name, ".symstr"))
908 return 1;
909
910 break;
911
912 // Sometimes we need to check by name...
913 default:
914 // There should be nothing here starting with .debug_* or .zdebug_*
915 if (pakfire_string_startswith(name, ".debug_"))
916 return 1;
917
918 else if (pakfire_string_startswith(name, ".zdebug_*"))
919 return 1;
920
921 // GDB symbol lookup
922 else if (pakfire_string_equals(name, ".gdb_index"))
923 return 1;
924
925 break;
926 }
927
928 return 0;
929 }
930
931 int pakfire_elf_is_stripped(struct pakfire_elf* self) {
932 int r;
933
934 switch (pakfire_elf_type(self)) {
935 // Do not check Relocatable Objects
936 case ET_REL:
937 return 0;
938
939 // Check everything else
940 default:
941 break;
942 }
943
944 // Run through all sections
945 r = pakfire_elf_foreach_section(self, SHT_NULL, __pakfire_elf_is_stripped, NULL);
946 if (r < 0)
947 return r;
948
949 // If the callback found something, the binary is not stripped
950 else if (r == 1)
951 return 0;
952
953 // Otherwise we assume the binary being stripped
954 return 1;
955 }
956
957 static int pakfire_elf_find_provides(struct pakfire_elf* self,
958 Elf_Scn* section, const GElf_Shdr* shdr, void* data) {
959 GElf_Verdaux verdaux = {};
960 GElf_Verdef verdef = {};
961 const char* version = NULL;
962 const char* base = NULL;
963 char*** provides = data;
964 int r;
965
966 // Fetch the section data
967 Elf_Data* d = elf_getdata(section, NULL);
968
969 size_t offset = 0;
970
971 while (offset < shdr->sh_size) {
972 if (!gelf_getverdef(d, offset, &verdef))
973 break;
974
975 size_t aux_offset = offset + verdef.vd_aux;
976
977 for (int i = 0; i < verdef.vd_cnt; i++) {
978 if (!gelf_getverdaux(d, aux_offset, &verdaux))
979 break;
980
981 // Fetch the version string
982 version = elf_strptr(self->elf, shdr->sh_link, verdaux.vda_name);
983
984 // Skip empty versions
985 if (!version || !*version)
986 continue;
987
988 // Is this the base?
989 if (verdef.vd_flags & VER_FLG_BASE) {
990 base = version;
991 break;
992 }
993
994 // Add it to the list
995 r = pakfire_strings_appendf(provides, "%s(%s)%s",
996 base, version, pakfire_elf_is_elf64(self) ? "(64bit)" : "");
997 if (r < 0)
998 return r;
999
1000 if (!verdaux.vda_next)
1001 break;
1002
1003 aux_offset += verdaux.vda_next;
1004 }
1005
1006 if (!verdef.vd_next)
1007 break;
1008
1009 offset += verdef.vd_next;
1010 }
1011
1012 return 0;
1013 }
1014
1015 int pakfire_elf_provides(struct pakfire_elf* self, char*** provides) {
1016 int r;
1017
1018 // Fetch the soname
1019 const char* soname = pakfire_elf_soname(self);
1020 if (soname) {
1021 r = pakfire_strings_appendf(provides,
1022 "%s()%s", soname, pakfire_elf_is_elf64(self) ? "(64bit)" : "");
1023 if (r < 0)
1024 return r;
1025 }
1026
1027 return pakfire_elf_foreach_section(self, SHT_GNU_verdef, pakfire_elf_find_provides, provides);
1028 }
1029
1030 static int pakfire_elf_find_requires(struct pakfire_elf* self,
1031 Elf_Scn* section, const GElf_Shdr* shdr, void* data) {
1032 GElf_Vernaux vernaux = {};
1033 GElf_Verneed verneed = {};
1034 const char* version = NULL;
1035 const char* name = NULL;
1036 char*** requires = data;
1037 GElf_Dyn dyn = {};
1038 size_t aux_offset;
1039 size_t offset;
1040 int r;
1041
1042 // Fetch the section data
1043 Elf_Data* d = elf_getdata(section, NULL);
1044
1045 switch (shdr->sh_type) {
1046 case SHT_DYNAMIC:
1047 for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; i++) {
1048 // Fetch the symbol
1049 if (!gelf_getdyn(d, i, &dyn))
1050 continue;
1051
1052 switch (dyn.d_tag) {
1053 case DT_NEEDED:
1054 name = elf_strptr(self->elf, shdr->sh_link, dyn.d_un.d_val);
1055
1056 // Skip empty names (this should not happen)
1057 if (!name || !*name)
1058 continue;
1059
1060 DEBUG(self->ctx, "%s depends on %s\n", self->path, name);
1061
1062 // Add it to the list
1063 r = pakfire_strings_appendf(requires, "%s()%s",
1064 name, pakfire_elf_is_elf64(self) ? "(64bit)" : "");
1065 if (r < 0)
1066 return r;
1067 break;
1068 }
1069 }
1070 break;
1071
1072 case SHT_GNU_verneed:
1073 offset = 0;
1074
1075 while (offset < shdr->sh_size) {
1076 if (!gelf_getverneed(d, offset, &verneed))
1077 break;
1078
1079 // Fetch the library name
1080 name = elf_strptr(self->elf, shdr->sh_link, verneed.vn_file);
1081 if (!name || !*name)
1082 continue;
1083
1084 aux_offset = offset + verneed.vn_aux;
1085
1086 for (int i = 0; i < verneed.vn_cnt; i++) {
1087 if (!gelf_getvernaux(d, aux_offset, &vernaux))
1088 break;
1089
1090 // Fetch the version string
1091 version = elf_strptr(self->elf, shdr->sh_link, vernaux.vna_name);
1092
1093 // Skip empty versions
1094 if (!version || !*version)
1095 continue;
1096
1097 // Add it to the list
1098 r = pakfire_strings_appendf(requires, "%s(%s)%s",
1099 name, version, pakfire_elf_is_elf64(self) ? "(64bit)" : "");
1100 if (r < 0)
1101 return r;
1102
1103 if (!vernaux.vna_next)
1104 break;
1105
1106 aux_offset += vernaux.vna_next;
1107 }
1108
1109 if (!verneed.vn_next)
1110 break;
1111
1112 offset += verneed.vn_next;
1113 }
1114 break;
1115
1116 default:
1117 break;
1118 }
1119
1120 return 0;
1121 }
1122
1123 int pakfire_elf_requires(struct pakfire_elf* self, char*** requires) {
1124 return pakfire_elf_foreach_section(self, SHT_NULL, pakfire_elf_find_requires, requires);
1125 }
1126
1127 /*
1128 libdw does not seem to export the error codes in their header files,
1129 although there is a function to retrieve them...
1130 */
1131 #ifndef DWARF_E_NO_DWARF
1132 #define DWARF_E_NO_DWARF 6
1133 #endif
1134
1135 int pakfire_elf_foreach_source_file(struct pakfire_elf* self,
1136 pakfire_elf_foreach_source_file_callback callback, void* data) {
1137 const char* filename = NULL;
1138 char basename[PATH_MAX];
1139 char path[PATH_MAX];
1140 Dwarf* dwarf = NULL;
1141 Dwarf_Files* files = NULL;
1142 Dwarf_Die* die = NULL;
1143 Dwarf_Off offset = 0;
1144 Dwarf_Off next_offset;
1145 size_t cu_header_length;
1146 Dwarf_Die die_mem;
1147 size_t count;
1148 int r;
1149
1150 // Read DWARF information
1151 dwarf = dwarf_begin(self->fd, DWARF_C_READ);
1152 if (!dwarf) {
1153 switch (dwarf_errno()) {
1154 // If we don't have any DWARF information there is nothing to do
1155 case DWARF_E_NO_DWARF:
1156 r = 0;
1157 goto ERROR;
1158
1159 default:
1160 ERROR(self->ctx, "Could not initialize DWARF context: %s\n", dwarf_errmsg(-1));
1161 r = -errno;
1162 goto ERROR;
1163 }
1164 }
1165
1166 for (;;) {
1167 // Fetch the next compilation unit
1168 r = dwarf_nextcu(dwarf, offset, &next_offset, &cu_header_length, NULL, NULL, NULL);
1169 if (r < 0)
1170 goto ERROR;
1171
1172 // Fetch the Debug Information Entry
1173 die = dwarf_offdie(dwarf, offset + cu_header_length, &die_mem);
1174 if (!die)
1175 break;
1176
1177 // Fetch the source files
1178 r = dwarf_getsrcfiles(die, &files, &count);
1179 if (r < 0)
1180 goto NEXT;
1181
1182 // Iterate over all files...
1183 for (unsigned int i = 0; i < count; i++) {
1184 // Fetch the filename
1185 filename = dwarf_filesrc(files, i, NULL, NULL);
1186
1187 // Copy to the stack
1188 r = pakfire_string_set(path, filename);
1189 if (r < 0)
1190 goto ERROR;
1191
1192 // Normalize the path
1193 r = pakfire_path_normalize(path);
1194 if (r < 0)
1195 goto ERROR;
1196
1197 // Determine the basename
1198 r = pakfire_path_basename(basename, filename);
1199 if (r < 0)
1200 goto ERROR;
1201
1202 // Ignore things like <artificial> or <built-in>
1203 if (pakfire_string_startswith(basename, "<")
1204 && pakfire_string_endswith(basename, ">"))
1205 continue;
1206
1207 // Call the callback
1208 r = callback(self->ctx, self, path, data);
1209 if (r)
1210 goto ERROR;
1211 }
1212
1213 NEXT:
1214 offset = next_offset;
1215 }
1216
1217 ERROR:
1218 if (dwarf)
1219 dwarf_end(dwarf);
1220
1221 return r;
1222 }