]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/file.c
Hardening: Declare content of /usr/lib/grub as firmware files
[people/stevee/pakfire.git] / src / libpakfire / file.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2014 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 <fnmatch.h>
23 #include <libgen.h>
24 #include <limits.h>
25 #include <linux/limits.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/capability.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <time.h>
32
33 #include <archive_entry.h>
34
35 #include <gelf.h>
36
37 #include <pakfire/constants.h>
38 #include <pakfire/digest.h>
39 #include <pakfire/fhs.h>
40 #include <pakfire/file.h>
41 #include <pakfire/logging.h>
42 #include <pakfire/pakfire.h>
43 #include <pakfire/private.h>
44 #include <pakfire/string.h>
45 #include <pakfire/util.h>
46
47 enum pakfire_file_verification_status {
48 PAKFIRE_FILE_NOENT = (1 << 0),
49 PAKFIRE_FILE_TYPE_CHANGED = (1 << 1),
50 PAKFIRE_FILE_PERMISSIONS_CHANGED = (1 << 2),
51 PAKFIRE_FILE_DEV_CHANGED = (1 << 3),
52 PAKFIRE_FILE_SIZE_CHANGED = (1 << 4),
53 PAKFIRE_FILE_OWNER_CHANGED = (1 << 5),
54 PAKFIRE_FILE_GROUP_CHANGED = (1 << 6),
55 PAKFIRE_FILE_CTIME_CHANGED = (1 << 7),
56 PAKFIRE_FILE_MTIME_CHANGED = (1 << 8),
57 PAKFIRE_FILE_PAYLOAD_CHANGED = (1 << 9),
58 };
59
60 struct pakfire_file {
61 struct pakfire* pakfire;
62 int nrefs;
63
64 // The relative path
65 char path[PATH_MAX];
66
67 // The absolute path in the file system
68 char abspath[PATH_MAX];
69
70 // File Ownership
71 char uname[LOGIN_NAME_MAX];
72 char gname[LOGIN_NAME_MAX];
73
74 // Stat
75 struct stat st;
76
77 // Capabilities
78 cap_t caps;
79
80 // Flags
81 int flags;
82
83 // Link destinations
84 char hardlink[PATH_MAX];
85 char symlink[PATH_MAX];
86
87 // Digests
88 struct pakfire_digests digests;
89
90 // MIME Type
91 char mimetype[NAME_MAX];
92
93 // Class
94 int class;
95
96 // Verification Status
97 int verify_status;
98
99 // File Issues
100 int issues;
101 int check_done:1;
102
103 #warning TODO data
104 //int is_datafile;
105 };
106
107 /*
108 Capabilities
109 */
110 static int pakfire_file_read_fcaps(struct pakfire_file* file,
111 const struct vfs_cap_data* cap_data, size_t length) {
112 int max = 0;
113 int r;
114
115 uint32_t magic_etc = le32toh(cap_data->magic_etc);
116
117 // Which version are we dealing with?
118 switch (magic_etc & VFS_CAP_REVISION_MASK) {
119 case VFS_CAP_REVISION_1:
120 length -= XATTR_CAPS_SZ_1;
121 max = VFS_CAP_U32_1;
122 break;
123
124 case VFS_CAP_REVISION_2:
125 length -= XATTR_CAPS_SZ_2;
126 max = VFS_CAP_U32_2;
127 break;
128
129 case VFS_CAP_REVISION_3:
130 length -= XATTR_CAPS_SZ_3;
131 max = VFS_CAP_U32_3;
132 break;
133
134 // Unknown version
135 default:
136 errno = EINVAL;
137 return 1;
138 }
139
140 // Check if we have received the correct data
141 if (length) {
142 errno = EINVAL;
143 return 1;
144 }
145
146 // Allocate capabilities
147 file->caps = cap_init();
148 if (!file->caps) {
149 ERROR(file->pakfire, "Could not allocate capabilities: %m\n");
150 r = 1;
151 goto ERROR;
152 }
153
154 int mask;
155 int index;
156
157 int cap_permitted;
158 int cap_inheritable;
159 int cap_effective = 0;
160
161 for (unsigned int cap = 0; cap_valid(cap); cap++) {
162 // Find the index where to find this cap
163 index = CAP_TO_INDEX(cap);
164 mask = CAP_TO_MASK(cap);
165
166 // End if we have reached the end of the data
167 if (index > max)
168 break;
169
170 // Check for permitted/inheritable flag set
171 cap_permitted = le32toh(cap_data->data[index].permitted) & mask;
172 cap_inheritable = le32toh(cap_data->data[index].inheritable) & mask;
173
174 // Check for effective
175 if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
176 cap_effective = cap_permitted | cap_inheritable;
177
178 cap_value_t caps[] = { cap };
179
180 if (cap_permitted) {
181 r = cap_set_flag(file->caps, CAP_PERMITTED, 1, caps, CAP_SET);
182 if (r) {
183 ERROR(file->pakfire, "Could not set capability %d: %m\n", cap);
184 goto ERROR;
185 }
186 }
187
188 if (cap_inheritable) {
189 r = cap_set_flag(file->caps, CAP_INHERITABLE, 1, caps, CAP_SET);
190 if (r) {
191 ERROR(file->pakfire, "Could not set capability %d: %m\n", cap);
192 goto ERROR;
193 }
194 }
195
196 if (cap_effective) {
197 r = cap_set_flag(file->caps, CAP_EFFECTIVE, 1, caps, CAP_SET);
198 if (r) {
199 ERROR(file->pakfire, "Could not set capability %d: %m\n", cap);
200 goto ERROR;
201 }
202 }
203 }
204
205 #ifdef ENABLE_DEBUG
206 char* text = cap_to_text(file->caps, NULL);
207 if (text) {
208 DEBUG(file->pakfire, "%s: Capabilities %s\n", file->path, text);
209 cap_free(text);
210 }
211 #endif
212
213 return 0;
214
215 ERROR:
216 if (file->caps) {
217 cap_free(file->caps);
218 file->caps = NULL;
219 }
220
221 return r;
222 }
223
224 int pakfire_file_write_fcaps(struct pakfire_file* file, struct vfs_cap_data* cap_data) {
225 cap_flag_value_t cap_permitted;
226 cap_flag_value_t cap_inheritable;
227 cap_flag_value_t cap_effective;
228 int r;
229
230 // This should not be called when we have no caps
231 if (!file->caps) {
232 errno = EINVAL;
233 return 1;
234 }
235
236 uint32_t magic = VFS_CAP_REVISION_2;
237
238 for (unsigned int cap = 0; cap_valid(cap); cap++) {
239 // Find the index where to find this cap
240 int index = CAP_TO_INDEX(cap);
241 int mask = CAP_TO_MASK(cap);
242
243 // Fetch CAP_PERMITTED
244 r = cap_get_flag(file->caps, cap, CAP_PERMITTED, &cap_permitted);
245 if (r) {
246 ERROR(file->pakfire, "Could not fetch capability %d: %m\n", cap);
247 goto ERROR;
248 }
249
250 // Fetch CAP_INHERITABLE
251 r = cap_get_flag(file->caps, cap, CAP_INHERITABLE, &cap_inheritable);
252 if (r) {
253 ERROR(file->pakfire, "Could not fetch capability %d: %m\n", cap);
254 goto ERROR;
255 }
256
257 // Fetch CAP_EFFECTIVE
258 r = cap_get_flag(file->caps, cap, CAP_EFFECTIVE, &cap_effective);
259 if (r) {
260 ERROR(file->pakfire, "Could not fetch capability %d: %m\n", cap);
261 goto ERROR;
262 }
263
264 // Store CAP_PERMITTED
265 if (cap_permitted)
266 cap_data->data[index].permitted |= htole32(mask);
267
268 // Store CAP_INHERITED
269 if (cap_inheritable)
270 cap_data->data[index].inheritable |= htole32(mask);
271
272 // Set EFFECTIVE flag if CAP_EFFECTIVE is set
273 if (cap_effective)
274 magic |= VFS_CAP_FLAGS_EFFECTIVE;
275 }
276
277 // Store the magic value
278 cap_data->magic_etc = htole32(magic);
279
280 ERROR:
281 return r;
282 }
283
284 static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct archive_entry* entry) {
285 char* buffer = NULL;
286 const char* path = NULL;
287 const char* attr = NULL;
288 const void* value = NULL;
289 size_t size = 0;
290 int r = 0;
291
292 // Set abspath
293 path = archive_entry_sourcepath(entry);
294 if (path) {
295 // Make path absolute
296 path = pakfire_path_abspath(path);
297 if (!path) {
298 r = 1;
299 goto ERROR;
300 }
301
302 // Set
303 r = pakfire_file_set_abspath(file, path);
304 if (r) {
305 ERROR(file->pakfire, "Could not set abspath: %m\n");
306 goto ERROR;
307 }
308 }
309
310 // Set path
311 path = archive_entry_pathname(entry);
312 if (path) {
313 r = pakfire_file_set_path(file, path);
314 if (r) {
315 ERROR(file->pakfire, "Could not set path: %m\n");
316 goto ERROR;
317 }
318 }
319
320 // Set links
321 pakfire_file_set_hardlink(file, archive_entry_hardlink(entry));
322 pakfire_file_set_symlink(file, archive_entry_symlink(entry));
323
324 pakfire_file_set_nlink(file, archive_entry_nlink(entry));
325 pakfire_file_set_inode(file, archive_entry_ino64(entry));
326 pakfire_file_set_dev(file, archive_entry_dev(entry));
327
328 // Set size
329 pakfire_file_set_size(file, archive_entry_size(entry));
330
331 // Set mode
332 pakfire_file_set_mode(file, archive_entry_mode(entry));
333
334 // Set dev type
335 if (archive_entry_dev_is_set(entry))
336 pakfire_file_set_dev(file, archive_entry_dev(entry));
337
338 // Set uname
339 pakfire_file_set_uname(file, archive_entry_uname(entry));
340
341 // Set gname
342 pakfire_file_set_gname(file, archive_entry_gname(entry));
343
344 // Set times
345 pakfire_file_set_ctime(file, archive_entry_ctime(entry));
346 pakfire_file_set_mtime(file, archive_entry_mtime(entry));
347
348 // Reset iterating over extended attributes
349 archive_entry_xattr_reset(entry);
350
351 // Read any extended attributes
352 while (archive_entry_xattr_next(entry, &attr, &value, &size) == ARCHIVE_OK) {
353 // Config Files
354 if (strcmp(attr, "PAKFIRE.config") == 0) {
355 r = pakfire_file_set_flags(file, PAKFIRE_FILE_CONFIG);
356 if (r)
357 goto ERROR;
358
359 // MIME type
360 } else if (strcmp(attr, "PAKFIRE.mimetype") == 0) {
361 // Copy the value into a NULL-terminated buffer
362 r = asprintf(&buffer, "%.*s", (int)size, (const char*)value);
363 if (r < 0)
364 goto ERROR;
365
366 // Assign the value
367 r = pakfire_file_set_mimetype(file, buffer);
368 if (r)
369 goto ERROR;
370
371 // Digest: SHA-3-512
372 } else if (strcmp(attr, "PAKFIRE.digests.sha3_512") == 0) {
373 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_512, value, size);
374 if (r)
375 goto ERROR;
376
377 // Digest: SHA-3-256
378 } else if (strcmp(attr, "PAKFIRE.digests.sha3_256") == 0) {
379 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_256, value, size);
380 if (r)
381 goto ERROR;
382
383 // Digest: BLAKE2b512
384 } else if (strcmp(attr, "PAKFIRE.digests.blake2b512") == 0) {
385 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2B512, value, size);
386 if (r)
387 goto ERROR;
388
389 // Digest: BLAKE2s256
390 } else if (strcmp(attr, "PAKFIRE.digests.blake2s256") == 0) {
391 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2S256, value, size);
392 if (r)
393 goto ERROR;
394
395 // Digest: SHA-2-512
396 } else if (strcmp(attr, "PAKFIRE.digests.sha2_512") == 0) {
397 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_512, value, size);
398 if (r)
399 goto ERROR;
400
401 // Digest: SHA-2-256
402 } else if (strcmp(attr, "PAKFIRE.digests.sha2_256") == 0) {
403 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_256, value, size);
404 if (r)
405 goto ERROR;
406
407 // Capabilities
408 } else if (strcmp(attr, "security.capability") == 0) {
409 r = pakfire_file_read_fcaps(file, value, size);
410 if (r)
411 goto ERROR;
412
413 } else {
414 DEBUG(file->pakfire, "Received an unknown extended attribute: %s\n", attr);
415 }
416 }
417
418 ERROR:
419 if (buffer)
420 free(buffer);
421
422 return r;
423 }
424
425 PAKFIRE_EXPORT int pakfire_file_create(struct pakfire_file** file, struct pakfire* pakfire) {
426 struct pakfire_file* f = calloc(1, sizeof(*f));
427 if (!f)
428 return 1;
429
430 // Store reference to Pakfire
431 f->pakfire = pakfire_ref(pakfire);
432
433 // Initialize reference counter
434 f->nrefs = 1;
435
436 *file = f;
437 return 0;
438 }
439
440 int pakfire_file_create_from_path(struct pakfire_file** file,
441 struct pakfire* pakfire, const char* path) {
442 struct archive* reader = NULL;
443 struct archive_entry* entry = NULL;
444 int r = 1;
445
446 // Allocate a reader
447 reader = pakfire_make_archive_disk_reader(pakfire, 0);
448 if (!reader)
449 goto ERROR;
450
451 // Allocate a new archive entry
452 entry = archive_entry_new();
453 if (!entry)
454 goto ERROR;
455
456 // Set source path
457 archive_entry_copy_sourcepath(entry, path);
458
459 // Read all file attributes from disk
460 r = archive_read_disk_entry_from_file(reader, entry, -1, NULL);
461 if (r) {
462 ERROR(pakfire, "Could not read from %s: %m\n", path);
463 goto ERROR;
464 }
465
466 // Create file
467 r = pakfire_file_create_from_archive_entry(file, pakfire, entry);
468 if (r)
469 goto ERROR;
470
471 ERROR:
472 if (r)
473 ERROR(pakfire, "Could not create file from path %s: %m\n", path);
474 if (entry)
475 archive_entry_free(entry);
476 if (reader)
477 archive_read_free(reader);
478
479 return r;
480 }
481
482 int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire,
483 struct archive_entry* entry) {
484 int r = pakfire_file_create(file, pakfire);
485 if (r)
486 return r;
487
488 // Copy archive entry
489 r = pakfire_file_from_archive_entry(*file, entry);
490 if (r)
491 goto ERROR;
492
493 return 0;
494
495 ERROR:
496 pakfire_file_unref(*file);
497 *file = NULL;
498
499 return r;
500 }
501
502 struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int digest_types) {
503 struct vfs_cap_data cap_data = {};
504 const char* path = NULL;
505 int r;
506
507 struct archive_entry* entry = archive_entry_new();
508 if (!entry) {
509 ERROR(file->pakfire, "Could not allocate archive entry: %m\n");
510 return NULL;
511 }
512
513 // Set source path
514 archive_entry_copy_sourcepath(entry, file->abspath);
515
516 // Set path
517 path = pakfire_file_get_path(file);
518 if (path && *path == '/') {
519 archive_entry_copy_pathname(entry, path + 1);
520 }
521
522 // Set links
523 if (*file->hardlink)
524 archive_entry_set_hardlink(entry, file->hardlink);
525 if (*file->symlink)
526 archive_entry_set_symlink(entry, file->symlink);
527
528 archive_entry_set_nlink(entry, pakfire_file_get_nlink(file));
529 archive_entry_set_ino64(entry, pakfire_file_get_inode(file));
530 archive_entry_set_dev(entry, pakfire_file_get_dev(file));
531
532 // Set size
533 archive_entry_set_size(entry, pakfire_file_get_size(file));
534
535 // Set mode
536 archive_entry_set_mode(entry, pakfire_file_get_mode(file));
537
538 // Set uname
539 archive_entry_set_uname(entry, pakfire_file_get_uname(file));
540
541 // Set gname
542 archive_entry_set_gname(entry, pakfire_file_get_gname(file));
543
544 // Set times
545 archive_entry_set_ctime(entry, pakfire_file_get_ctime(file), 0);
546 archive_entry_set_mtime(entry, pakfire_file_get_mtime(file), 0);
547
548 // Flags
549 if (pakfire_file_has_flag(file, PAKFIRE_FILE_CONFIG)) {
550 archive_entry_xattr_add_entry(entry,
551 "PAKFIRE.config", "1", strlen("1"));
552 }
553
554 // Set MIME type
555 const char* mimetype = pakfire_file_get_mimetype(file);
556 if (mimetype) {
557 archive_entry_xattr_add_entry(entry,
558 "PAKFIRE.mimetype", mimetype, strlen(mimetype));
559 }
560
561 // Compute any required file digests
562 r = pakfire_file_compute_digests(file, digest_types);
563 if (r)
564 goto ERROR;
565
566 // Copy digests
567
568 // SHA-3-512
569 if ((digest_types && PAKFIRE_DIGEST_SHA3_512)
570 && pakfire_digest_set(file->digests.sha3_512))
571 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_512",
572 file->digests.sha3_512, sizeof(file->digests.sha3_512));
573
574 // SHA-3-256
575 if ((digest_types && PAKFIRE_DIGEST_SHA3_256) &&
576 pakfire_digest_set(file->digests.sha3_256))
577 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_256",
578 file->digests.sha3_256, sizeof(file->digests.sha3_256));
579
580 // BLAKE2b512
581 if ((digest_types && PAKFIRE_DIGEST_BLAKE2B512) &&
582 pakfire_digest_set(file->digests.blake2b512))
583 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2b512",
584 file->digests.blake2b512, sizeof(file->digests.blake2b512));
585
586 // BLAKE2s256
587 if ((digest_types && PAKFIRE_DIGEST_BLAKE2S256) &&
588 pakfire_digest_set(file->digests.blake2s256))
589 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2s256",
590 file->digests.blake2s256, sizeof(file->digests.blake2s256));
591
592 // SHA-2-512
593 if ((digest_types && PAKFIRE_DIGEST_SHA2_512) &&
594 pakfire_digest_set(file->digests.sha2_512))
595 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_512",
596 file->digests.sha2_512, sizeof(file->digests.sha2_512));
597
598 // SHA-2-256
599 if ((digest_types && PAKFIRE_DIGEST_SHA2_512) &&
600 pakfire_digest_set(file->digests.sha2_256))
601 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_256",
602 file->digests.sha2_256, sizeof(file->digests.sha2_256));
603
604 // Capabilities
605 if (file->caps) {
606 r = pakfire_file_write_fcaps(file, &cap_data);
607 if (r) {
608 ERROR(file->pakfire, "Could not export capabilities: %m\n");
609 goto ERROR;
610 }
611
612 // Store capabilities in archive entry
613 archive_entry_xattr_add_entry(entry,
614 "security.capability", &cap_data, sizeof(cap_data));
615 }
616
617 return entry;
618
619 ERROR:
620 if (entry)
621 archive_entry_free(entry);
622
623 return NULL;
624 }
625
626 static void pakfire_file_free(struct pakfire_file* file) {
627 // Free capabilities
628 if (file->caps)
629 cap_free(file->caps);
630
631 pakfire_unref(file->pakfire);
632 free(file);
633 }
634
635 PAKFIRE_EXPORT struct pakfire_file* pakfire_file_ref(struct pakfire_file* file) {
636 file->nrefs++;
637
638 return file;
639 }
640
641 PAKFIRE_EXPORT struct pakfire_file* pakfire_file_unref(struct pakfire_file* file) {
642 if (--file->nrefs > 0)
643 return file;
644
645 pakfire_file_free(file);
646 return NULL;
647 }
648
649 /*
650 Flags
651 */
652
653 int pakfire_file_has_flag(struct pakfire_file* file, int flag) {
654 return file->flags & flag;
655 }
656
657 int pakfire_file_set_flags(struct pakfire_file* file, int flag) {
658 file->flags |= flag;
659
660 return 0;
661 }
662
663 #define pakfire_file_strmode(file, buffer) \
664 __pakfire_file_strmode(file, buffer, sizeof(buffer))
665
666 static int __pakfire_file_strmode(struct pakfire_file* file, char* s, const size_t length) {
667 int r;
668
669 static const mode_t permbits[] = {
670 0400,
671 0200,
672 0100,
673 0040,
674 0020,
675 0010,
676 0004,
677 0002,
678 0001
679 };
680
681 const mode_t mode = pakfire_file_get_mode(file);
682 const mode_t type = pakfire_file_get_type(file);
683
684 // Set some default string
685 r = __pakfire_string_set(s, length, "?rwxrwxrwx ");
686 if (r)
687 return r;
688
689 switch (type) {
690 case S_IFREG:
691 s[0] = '-';
692 break;
693
694 case S_IFBLK:
695 s[0] = 'b';
696 break;
697
698 case S_IFCHR:
699 s[0] = 'c';
700 break;
701
702 case S_IFDIR:
703 s[0] = 'd';
704 break;
705
706 case S_IFLNK:
707 s[0] = 'l';
708 break;
709
710 case S_IFSOCK:
711 s[0] = 's';
712 break;
713
714 case S_IFIFO:
715 s[0] = 'p';
716 break;
717
718 default:
719 if (*file->hardlink) {
720 s[0] = 'h';
721 break;
722 }
723 }
724
725 for (unsigned int i = 0; i < 9; i++) {
726 if (mode & permbits[i])
727 continue;
728
729 s[i+1] = '-';
730 }
731
732 if (mode & S_ISUID) {
733 if (mode & 0100)
734 s[3] = 's';
735 else
736 s[3] = 'S';
737 }
738
739 if (mode & S_ISGID) {
740 if (mode & 0010)
741 s[6] = 's';
742 else
743 s[6] = 'S';
744 }
745
746 if (mode & S_ISVTX) {
747 if (mode & 0001)
748 s[9] = 't';
749 else
750 s[9] = 'T';
751 }
752
753 #if 0
754 if (file->caps)
755 s[10] = '+';
756 #endif
757
758 return 0;
759 }
760
761 char* pakfire_file_dump(struct pakfire_file* file, int flags) {
762 char* buffer = "";
763 int r;
764
765 char mode[12];
766 char time[32];
767
768 // Format mode
769 if (flags & PAKFIRE_FILE_DUMP_MODE) {
770 r = pakfire_file_strmode(file, mode);
771 if (r)
772 goto ERROR;
773
774 r = asprintf(&buffer, "%s %s", buffer, mode);
775 if (r < 0)
776 goto ERROR;
777 }
778
779 // Format ownership
780 if (flags & PAKFIRE_FILE_DUMP_OWNERSHIP) {
781 r = asprintf(&buffer, "%s %s/%s", buffer, file->uname, file->gname);
782 if (r < 0)
783 goto ERROR;
784 }
785
786 // Format size
787 if (flags & PAKFIRE_FILE_DUMP_SIZE) {
788 r = asprintf(&buffer, "%s %8zu", buffer, file->st.st_size);
789 if (r < 0)
790 goto ERROR;
791 }
792
793 // Format time
794 if (flags & PAKFIRE_FILE_DUMP_TIME) {
795 r = pakfire_strftime(time, "%Y-%m-%d %H:%M", file->st.st_ctime);
796 if (r)
797 goto ERROR;
798
799 r = asprintf(&buffer, "%s %s", buffer, time);
800 if (r < 0)
801 goto ERROR;
802 }
803
804 // Format path
805 r = asprintf(&buffer, "%s %s", buffer, file->path);
806 if (r < 0)
807 goto ERROR;
808
809 // Append symlink target
810 if (flags & PAKFIRE_FILE_DUMP_LINK_TARGETS) {
811 switch (pakfire_file_get_type(file)) {
812 case S_IFLNK:
813 r = asprintf(&buffer, "%s -> %s", buffer, file->symlink);
814 if (r < 0)
815 return NULL;
816
817 default:
818 break;
819 }
820 }
821
822 // Dump Issues
823 if (flags & PAKFIRE_FILE_DUMP_ISSUES) {
824 if (file->issues & PAKFIRE_FILE_FHS_ERROR) {
825 r = asprintf(&buffer, "%s [FHS-ERROR]", buffer);
826 if (r < 0)
827 goto ERROR;
828 }
829
830 if (file->issues & PAKFIRE_FILE_MISSING_DEBUGINFO) {
831 r = asprintf(&buffer, "%s [MISSING-DEBUGINFO]", buffer);
832 if (r < 0)
833 goto ERROR;
834 }
835
836 // Stack-smashing Protection
837 if (file->issues & PAKFIRE_FILE_MISSING_SSP) {
838 r = asprintf(&buffer, "%s [MISSING-SSP]", buffer);
839 if (r < 0)
840 goto ERROR;
841 }
842
843 // Position-independent Executable
844 if (file->issues & PAKFIRE_FILE_MISSING_PIE) {
845 r = asprintf(&buffer, "%s [MISSING-PIE]", buffer);
846 if (r < 0)
847 goto ERROR;
848 }
849
850 // Executable Stack
851 if (file->issues & PAKFIRE_FILE_EXECSTACK) {
852 r = asprintf(&buffer, "%s [EXECSTACK]", buffer);
853 if (r < 0)
854 goto ERROR;
855 }
856
857 // Not RELRO
858 if (file->issues & PAKFIRE_FILE_NO_RELRO) {
859 r = asprintf(&buffer, "%s [NO-RELRO]", buffer);
860 if (r < 0)
861 goto ERROR;
862 }
863
864 // Has RUNPATH?
865 if (file->issues & PAKFIRE_FILE_HAS_RUNPATH) {
866 r = asprintf(&buffer, "%s [HAS-RUNPATH]", buffer);
867 if (r < 0)
868 goto ERROR;
869 }
870
871 // Invalid capabilities
872 if (file->issues & PAKFIRE_FILE_INVALID_CAPS) {
873 r = asprintf(&buffer, "%s [INVALID-CAPS]", buffer);
874 if (r < 0)
875 goto ERROR;
876 }
877 }
878
879 return buffer;
880
881 ERROR:
882 if (buffer)
883 free(buffer);
884
885 return NULL;
886 }
887
888 PAKFIRE_EXPORT int pakfire_file_cmp(struct pakfire_file* file1, struct pakfire_file* file2) {
889 const char* path1 = pakfire_file_get_path(file1);
890 const char* path2 = pakfire_file_get_path(file2);
891
892 return strcmp(path1, path2);
893 }
894
895 const char* pakfire_file_get_abspath(struct pakfire_file* file) {
896 return file->abspath;
897 }
898
899 int pakfire_file_set_abspath(struct pakfire_file* file, const char* path) {
900 int r;
901
902 // Check if path is set and absolute
903 if (!path || *path != '/') {
904 errno = EINVAL;
905 return 1;
906 }
907
908 // Store the abspath
909 r = pakfire_string_set(file->abspath, path);
910 if (r)
911 goto ERROR;
912
913 // Store path if it isn't set, yet
914 if (!*file->path) {
915 r = pakfire_file_set_path(file, path);
916 if (r)
917 goto ERROR;
918 }
919
920 return r;
921
922 ERROR:
923 ERROR(file->pakfire, "Could not set abspath '%s': %m\n", path);
924 return r;
925 }
926
927 PAKFIRE_EXPORT const char* pakfire_file_get_path(struct pakfire_file* file) {
928 return file->path;
929 }
930
931 PAKFIRE_EXPORT int pakfire_file_set_path(struct pakfire_file* file, const char* path) {
932 int r = 1;
933
934 // Check if path is set
935 if (!path) {
936 errno = EINVAL;
937 goto ERROR;
938 }
939
940 // Strip any leading dots from paths
941 if (pakfire_string_startswith(path, "./"))
942 path++;
943
944 switch (*path) {
945 // Just store the path if it is absolute
946 case '/':
947 r = pakfire_string_set(file->path, path);
948 if (r)
949 goto ERROR;
950 break;
951
952 // Handle relative paths
953 default:
954 r = pakfire_string_format(file->path, "/%s", path);
955 if (r)
956 goto ERROR;
957 break;
958 }
959
960 // Set abspath if it isn't set, yet
961 if (!*file->abspath) {
962 r = pakfire_file_set_abspath(file, file->path);
963 if (r)
964 goto ERROR;
965 }
966
967 return r;
968
969 ERROR:
970 ERROR(file->pakfire, "Could not set path '%s': %m\n", path);
971 return r;
972 }
973
974 PAKFIRE_EXPORT const char* pakfire_file_get_hardlink(struct pakfire_file* file) {
975 if (!*file->hardlink)
976 return NULL;
977
978 return file->hardlink;
979 }
980
981 PAKFIRE_EXPORT void pakfire_file_set_hardlink(struct pakfire_file* file, const char* link) {
982 pakfire_string_set(file->hardlink, link);
983 }
984
985 PAKFIRE_EXPORT const char* pakfire_file_get_symlink(struct pakfire_file* file) {
986 if (!*file->symlink)
987 return NULL;
988
989 return file->symlink;
990 }
991
992 PAKFIRE_EXPORT void pakfire_file_set_symlink(struct pakfire_file* file, const char* link) {
993 pakfire_string_set(file->symlink, link);
994 }
995
996 PAKFIRE_EXPORT nlink_t pakfire_file_get_nlink(struct pakfire_file* file) {
997 return file->st.st_nlink;
998 }
999
1000 PAKFIRE_EXPORT void pakfire_file_set_nlink(struct pakfire_file* file, const nlink_t nlink) {
1001 file->st.st_nlink = nlink;
1002 }
1003
1004 PAKFIRE_EXPORT ino_t pakfire_file_get_inode(struct pakfire_file* file) {
1005 return file->st.st_ino;
1006 }
1007
1008 PAKFIRE_EXPORT void pakfire_file_set_inode(struct pakfire_file* file, const ino_t ino) {
1009 file->st.st_ino = ino;
1010 }
1011
1012 PAKFIRE_EXPORT dev_t pakfire_file_get_dev(struct pakfire_file* file) {
1013 return file->st.st_dev;
1014 }
1015
1016 PAKFIRE_EXPORT void pakfire_file_set_dev(struct pakfire_file* file, const dev_t dev) {
1017 file->st.st_dev = dev;
1018 }
1019
1020 PAKFIRE_EXPORT int pakfire_file_get_type(struct pakfire_file* file) {
1021 return file->st.st_mode & S_IFMT;
1022 }
1023
1024 PAKFIRE_EXPORT off_t pakfire_file_get_size(struct pakfire_file* file) {
1025 return file->st.st_size;
1026 }
1027
1028 PAKFIRE_EXPORT void pakfire_file_set_size(struct pakfire_file* file, off_t size) {
1029 file->st.st_size = size;
1030 }
1031
1032 PAKFIRE_EXPORT const char* pakfire_file_get_uname(struct pakfire_file* file) {
1033 return file->uname;
1034 }
1035
1036 PAKFIRE_EXPORT int pakfire_file_set_uname(struct pakfire_file* file, const char* uname) {
1037 return pakfire_string_set(file->uname, uname);
1038 }
1039
1040 PAKFIRE_EXPORT const char* pakfire_file_get_gname(struct pakfire_file* file) {
1041 return file->gname;
1042 }
1043
1044 PAKFIRE_EXPORT int pakfire_file_set_gname(struct pakfire_file* file, const char* gname) {
1045 return pakfire_string_set(file->gname, gname);
1046 }
1047
1048 PAKFIRE_EXPORT mode_t pakfire_file_get_mode(struct pakfire_file* file) {
1049 return file->st.st_mode;
1050 }
1051
1052 PAKFIRE_EXPORT void pakfire_file_set_mode(struct pakfire_file* file, mode_t mode) {
1053 file->st.st_mode = mode;
1054 }
1055
1056 PAKFIRE_EXPORT mode_t pakfire_file_get_perms(struct pakfire_file* file) {
1057 return file->st.st_mode & ~S_IFMT;
1058 }
1059
1060 PAKFIRE_EXPORT void pakfire_file_set_perms(struct pakfire_file* file, const mode_t perms) {
1061 // Clear any previous permissions
1062 file->st.st_mode &= S_IFMT;
1063
1064 // Set new bits (with format cleared)
1065 file->st.st_mode |= ~S_IFMT & perms;
1066 }
1067
1068 static int pakfire_file_is_executable(struct pakfire_file* file) {
1069 return file->st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
1070 }
1071
1072 PAKFIRE_EXPORT time_t pakfire_file_get_ctime(struct pakfire_file* file) {
1073 return file->st.st_ctime;
1074 }
1075
1076 PAKFIRE_EXPORT void pakfire_file_set_ctime(struct pakfire_file* file, time_t time) {
1077 file->st.st_ctime = time;
1078 }
1079
1080 PAKFIRE_EXPORT time_t pakfire_file_get_mtime(struct pakfire_file* file) {
1081 return file->st.st_mtime;
1082 }
1083
1084 PAKFIRE_EXPORT void pakfire_file_set_mtime(struct pakfire_file* file, time_t time) {
1085 file->st.st_mtime = time;
1086 }
1087
1088 PAKFIRE_EXPORT const unsigned char* pakfire_file_get_digest(
1089 struct pakfire_file* file, const enum pakfire_digest_types type, size_t* length) {
1090
1091 switch (type) {
1092 case PAKFIRE_DIGEST_SHA3_512:
1093 if (!pakfire_digest_set(file->digests.sha3_512))
1094 return NULL;
1095
1096 if (length)
1097 *length = sizeof(file->digests.sha3_512);
1098
1099 return file->digests.sha3_512;
1100
1101 case PAKFIRE_DIGEST_SHA3_256:
1102 if (!pakfire_digest_set(file->digests.sha3_256))
1103 return NULL;
1104
1105 if (length)
1106 *length = sizeof(file->digests.sha3_256);
1107
1108 return file->digests.sha3_256;
1109
1110 case PAKFIRE_DIGEST_BLAKE2B512:
1111 if (!pakfire_digest_set(file->digests.blake2b512))
1112 return NULL;
1113
1114 if (length)
1115 *length = sizeof(file->digests.blake2b512);
1116
1117 return file->digests.blake2b512;
1118
1119 case PAKFIRE_DIGEST_BLAKE2S256:
1120 if (!pakfire_digest_set(file->digests.blake2s256))
1121 return NULL;
1122
1123 if (length)
1124 *length = sizeof(file->digests.blake2s256);
1125
1126 return file->digests.blake2s256;
1127
1128 case PAKFIRE_DIGEST_SHA2_512:
1129 if (!pakfire_digest_set(file->digests.sha2_512))
1130 return NULL;
1131
1132 if (length)
1133 *length = sizeof(file->digests.sha2_512);
1134
1135 return file->digests.sha2_512;
1136
1137 case PAKFIRE_DIGEST_SHA2_256:
1138 if (!pakfire_digest_set(file->digests.sha2_256))
1139 return NULL;
1140
1141 if (length)
1142 *length = sizeof(file->digests.sha2_256);
1143
1144 return file->digests.sha2_256;
1145
1146 case PAKFIRE_DIGEST_UNDEFINED:
1147 break;
1148 }
1149
1150 return NULL;
1151 }
1152
1153 PAKFIRE_EXPORT int pakfire_file_set_digest(struct pakfire_file* file,
1154 const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) {
1155 if (!digest) {
1156 errno = EINVAL;
1157 return 1;
1158 }
1159
1160 // Check buffer length
1161 if (pakfire_digest_length(type) != length) {
1162 ERROR(file->pakfire, "Digest has an incorrect length of %zu byte(s)\n", length);
1163 errno = ENOMSG;
1164 return 1;
1165 }
1166
1167 // Store the digest
1168 switch (type) {
1169 case PAKFIRE_DIGEST_SHA3_512:
1170 memcpy(file->digests.sha3_512, digest, sizeof(file->digests.sha3_512));
1171 break;
1172
1173 case PAKFIRE_DIGEST_SHA3_256:
1174 memcpy(file->digests.sha3_256, digest, sizeof(file->digests.sha3_256));
1175 break;
1176
1177 case PAKFIRE_DIGEST_BLAKE2B512:
1178 memcpy(file->digests.blake2b512, digest, sizeof(file->digests.blake2b512));
1179 break;
1180
1181 case PAKFIRE_DIGEST_BLAKE2S256:
1182 memcpy(file->digests.blake2s256, digest, sizeof(file->digests.blake2s256));
1183 break;
1184
1185 case PAKFIRE_DIGEST_SHA2_512:
1186 memcpy(file->digests.sha2_512, digest, sizeof(file->digests.sha2_512));
1187 break;
1188
1189 case PAKFIRE_DIGEST_SHA2_256:
1190 memcpy(file->digests.sha2_256, digest, sizeof(file->digests.sha2_256));
1191 break;
1192
1193 case PAKFIRE_DIGEST_UNDEFINED:
1194 errno = ENOTSUP;
1195 return 1;
1196 }
1197
1198 return 0;
1199 }
1200
1201 PAKFIRE_EXPORT int pakfire_file_has_caps(struct pakfire_file* file) {
1202 if (file->caps)
1203 return 1;
1204
1205 return 0;
1206 }
1207
1208 PAKFIRE_EXPORT char* pakfire_file_get_caps(struct pakfire_file* file) {
1209 char* copy = NULL;
1210 char* text = NULL;
1211 ssize_t length = 0;
1212
1213 if (file->caps) {
1214 text = cap_to_text(file->caps, &length);
1215 if (!text) {
1216 ERROR(file->pakfire, "Could not export capabilities: %m\n");
1217 goto ERROR;
1218 }
1219
1220 // libcap is being weird and uses its own allocator so we have to copy the string
1221 copy = strndup(text, length);
1222 if (!copy)
1223 goto ERROR;
1224 }
1225
1226 ERROR:
1227 if (text)
1228 cap_free(text);
1229
1230 return copy;
1231 }
1232
1233 static int pakfire_file_levels(struct pakfire_file* file) {
1234 if (!*file->path)
1235 return 0;
1236
1237 int levels = 0;
1238
1239 for (char* p = file->path; *p; p++) {
1240 if (*p == '/')
1241 levels++;
1242 }
1243
1244 return levels;
1245 }
1246
1247 FILE* pakfire_file_open(struct pakfire_file* file) {
1248 FILE* f = fopen(file->abspath, "r");
1249 if (!f)
1250 ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
1251
1252 return f;
1253 }
1254
1255 int pakfire_file_payload_matches(struct pakfire_file* file,
1256 const void* needle, const size_t length) {
1257 char buffer[1024 * 1024];
1258 FILE* f = NULL;
1259 void* p = NULL;
1260 int r;
1261
1262 // Only run for regular files
1263 if (!S_ISREG(file->st.st_mode))
1264 return 0;
1265
1266 // Skip empty files
1267 if (!file->st.st_size)
1268 return 0;
1269
1270 // Open the file
1271 f = pakfire_file_open(file);
1272 if (!f) {
1273 r = 1;
1274 goto ERROR;
1275 }
1276
1277 while (!feof(f)) {
1278 size_t bytes_read = fread(buffer, 1, sizeof(buffer), f);
1279
1280 // Raise any reading errors
1281 if (ferror(f)) {
1282 r = 1;
1283 goto ERROR;
1284 }
1285
1286 // Search for the needle
1287 p = memmem(buffer, bytes_read, needle, length);
1288 if (p) {
1289 r = 1;
1290 goto ERROR;
1291 }
1292 }
1293
1294 // No match
1295 r = 0;
1296
1297 ERROR:
1298 if (f)
1299 fclose(f);
1300
1301 return r;
1302 }
1303
1304 static int __pakfire_file_compute_digests(struct pakfire_file* file,
1305 struct pakfire_digests* digests, const int types) {
1306 FILE* f = NULL;
1307 int r = 1;
1308
1309 // Skip this for anything that isn't a regular file
1310 if (!S_ISREG(file->st.st_mode))
1311 return 0;
1312
1313 // Reset digests
1314 pakfire_digests_reset(digests, types);
1315
1316 // Open the file
1317 f = pakfire_file_open(file);
1318 if (!f)
1319 goto ERROR;
1320
1321 // Compute digests
1322 r = pakfire_digests_compute_from_file(file->pakfire, digests, types, f);
1323 if (r)
1324 goto ERROR;
1325
1326 ERROR:
1327 if (f)
1328 fclose(f);
1329
1330 return r;
1331 }
1332
1333 int pakfire_file_compute_digests(struct pakfire_file* file, const int types) {
1334 return __pakfire_file_compute_digests(file, &file->digests, types);
1335 }
1336
1337 static int pakfire_file_remove(struct pakfire_file* file) {
1338 int r;
1339
1340 if (!*file->abspath) {
1341 errno = EINVAL;
1342 return 1;
1343 }
1344
1345 DEBUG(file->pakfire, "Removing %s...\n", file->path);
1346
1347 switch (file->st.st_mode & S_IFMT) {
1348 // Call rmdir() for directories
1349 case S_IFDIR:
1350 r = rmdir(file->abspath);
1351 if (r) {
1352 switch (errno) {
1353 // Ignore when the directory is not empty
1354 case ENOTEMPTY:
1355 r = 0;
1356 break;
1357
1358 // Ignore if the directory didn't exist
1359 case ENOENT:
1360 r = 0;
1361 break;
1362
1363 // Ignore if the directory changed type
1364 case ENOTDIR:
1365 r = 0;
1366 break;
1367
1368 // Log anything else
1369 default:
1370 ERROR(file->pakfire, "Could not remove directory %s: %m\n", file->path);
1371 break;
1372 }
1373 }
1374 break;
1375
1376 // Call unlink() for everything else
1377 default:
1378 r = unlink(file->abspath);
1379 if (r) {
1380 switch (errno) {
1381 // Ignore if the file didn't exist
1382 case ENOENT:
1383 r = 0;
1384 break;
1385
1386 default:
1387 ERROR(file->pakfire, "Could not remove %s: %m\n", file->path);
1388 break;
1389 }
1390 }
1391 break;
1392 }
1393
1394 return r;
1395 }
1396
1397 int pakfire_file_symlink_target_exists(struct pakfire_file* file) {
1398 // Fail if this got called for anything that isn't a symlink
1399 if (!S_ISLNK(file->st.st_mode)) {
1400 errno = EINVAL;
1401 return -1;
1402 }
1403
1404 return pakfire_path_exists(file->abspath);
1405 }
1406
1407 /*
1408 MIME Type
1409 */
1410
1411 int pakfire_file_detect_mimetype(struct pakfire_file* file) {
1412 // Only process regular files
1413 if (!S_ISREG(file->st.st_mode))
1414 return 0;
1415
1416 // Skip if MIME type is already set
1417 if (*file->mimetype)
1418 return 0;
1419
1420 // Fetch the magic cookie
1421 magic_t magic = pakfire_get_magic(file->pakfire);
1422 if (!magic)
1423 return 1;
1424
1425 // Check the file
1426 const char* mimetype = magic_file(magic, file->abspath);
1427 if (!mimetype) {
1428 ERROR(file->pakfire, "Could not classify %s: %s\n", file->path, magic_error(magic));
1429 return 1;
1430 }
1431
1432 DEBUG(file->pakfire, "Classified %s as %s\n", file->path, mimetype);
1433
1434 // Store the value
1435 return pakfire_file_set_mimetype(file, mimetype);
1436 }
1437
1438 PAKFIRE_EXPORT const char* pakfire_file_get_mimetype(struct pakfire_file* file) {
1439 // Return nothing on an empty mimetype
1440 if (!*file->mimetype)
1441 return NULL;
1442
1443 return file->mimetype;
1444 }
1445
1446 PAKFIRE_EXPORT int pakfire_file_set_mimetype(
1447 struct pakfire_file* file, const char* mimetype) {
1448 // Store the value
1449 return pakfire_string_set(file->mimetype, mimetype);
1450 }
1451
1452 /*
1453 Classification
1454 */
1455
1456 static int setup_libelf(struct pakfire* pakfire) {
1457 // Initialize libelf
1458 if (elf_version(EV_CURRENT) == EV_NONE) {
1459 ERROR(pakfire, "Could not initialize libelf: %s\n", elf_errmsg(-1));
1460
1461 return 1;
1462 }
1463
1464 return 0;
1465 }
1466
1467 static int pakfire_file_classify_mode(struct pakfire_file* file) {
1468 // Check for regular files
1469 if (S_ISREG(file->st.st_mode)) {
1470 file->class |= PAKFIRE_FILE_REGULAR;
1471
1472 // Does the file have executable permissions?
1473 if (file->st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
1474 file->class |= PAKFIRE_FILE_EXECUTABLE;
1475
1476 // Check for directories
1477 } else if (S_ISDIR(file->st.st_mode))
1478 file->class |= PAKFIRE_FILE_DIRECTORY;
1479
1480 // Check for symlinks
1481 else if (S_ISLNK(file->st.st_mode))
1482 file->class |= PAKFIRE_FILE_SYMLINK;
1483
1484 // Check for character devices
1485 else if (S_ISCHR(file->st.st_mode))
1486 file->class |= PAKFIRE_FILE_CHARACTER;
1487
1488 // Check for block devices
1489 else if (S_ISBLK(file->st.st_mode))
1490 file->class |= PAKFIRE_FILE_BLOCK;
1491
1492 // Check for FIFO pipes
1493 else if (S_ISFIFO(file->st.st_mode))
1494 file->class |= PAKFIRE_FILE_FIFO;
1495
1496 // Check for sockets
1497 else if (S_ISSOCK(file->st.st_mode))
1498 file->class |= PAKFIRE_FILE_SOCKET;
1499
1500 return 0;
1501 }
1502
1503 static const struct pattern {
1504 const char* pattern;
1505 int class;
1506 } patterns[] = {
1507 { "*.a", PAKFIRE_FILE_STATIC_LIBRARY },
1508 { "*.la", PAKFIRE_FILE_LIBTOOL_ARCHIVE },
1509 { "*.pm", PAKFIRE_FILE_PERL },
1510 { "*.pc", PAKFIRE_FILE_PKGCONFIG },
1511 { "/usr/lib/firmware/*", PAKFIRE_FILE_FIRMWARE },
1512 { "/usr/lib/grub/*", PAKFIRE_FILE_FIRMWARE },
1513 { "/usr/lib*/ld-*.so*", PAKFIRE_FILE_RUNTIME_LINKER },
1514 { NULL },
1515 };
1516
1517 static int pakfire_file_classify_pattern(struct pakfire_file* file) {
1518 for (const struct pattern* p = patterns; p->pattern; p++) {
1519 if (pakfire_file_matches(file, p->pattern)) {
1520 file->class |= p->class;
1521 break;
1522 }
1523 }
1524
1525 return 0;
1526 }
1527
1528 static const struct mimetype {
1529 const char* mimetype;
1530 int class;
1531 } mimetypes[] = {
1532 { "text/x-perl", PAKFIRE_FILE_PERL },
1533 { NULL, 0 },
1534 };
1535
1536 static int pakfire_file_classify_magic(struct pakfire_file* file) {
1537 int r;
1538
1539 // Detect the MIME type
1540 r = pakfire_file_detect_mimetype(file);
1541 if (r)
1542 return r;
1543
1544 // Fetch the MIME type
1545 const char* mimetype = pakfire_file_get_mimetype(file);
1546 if (!mimetype)
1547 return 1;
1548
1549 // Match the MIME type with a flag
1550 for (const struct mimetype* m = mimetypes; m->mimetype; m++) {
1551 if (strcmp(m->mimetype, mimetype) == 0) {
1552 file->class |= m->class;
1553 break;
1554 }
1555 }
1556
1557 return 0;
1558 }
1559
1560 static int pakfire_file_classify_elf(struct pakfire_file* file) {
1561 FILE* f = NULL;
1562 Elf* elf = NULL;
1563 int r;
1564
1565 // Don't run this if we already know that file is an ELF file
1566 if (file->class & PAKFIRE_FILE_ELF)
1567 return 0;
1568
1569 // Setup libelf
1570 r = setup_libelf(file->pakfire);
1571 if (r)
1572 return r;
1573
1574 // Open the file
1575 f = fopen(file->abspath, "r");
1576 if (!f) {
1577 ERROR(file->pakfire, "Could not open %s: %m\n", file->path);
1578 return 1;
1579 }
1580
1581 // Try to open the ELF file
1582 elf = elf_begin(fileno(f), ELF_C_READ, NULL);
1583 if (!elf) {
1584 // We fail silently here, because this file might be in a different format
1585 goto ERROR;
1586 }
1587
1588 switch (elf_kind(elf)) {
1589 // Mark this file as an ELF file
1590 case ELF_K_ELF:
1591 file->class |= PAKFIRE_FILE_ELF;
1592 break;
1593
1594 // Ignore everything else
1595 default:
1596 break;
1597 }
1598
1599 ERROR:
1600 if (elf)
1601 elf_end(elf);
1602 if (f)
1603 fclose(f);
1604
1605 return 0;
1606 }
1607
1608 int pakfire_file_classify(struct pakfire_file* file) {
1609 int r;
1610
1611 if (!file->class) {
1612 // First, check the mode so that we won't run magic on directories, symlinks, ...
1613 r = pakfire_file_classify_mode(file);
1614 if (r)
1615 goto ERROR;
1616
1617 // Only run this for regular files
1618 if (file->class & PAKFIRE_FILE_REGULAR) {
1619 // Then check for patterns
1620 r = pakfire_file_classify_pattern(file);
1621 if (r)
1622 goto ERROR;
1623
1624 // After that, we will use libmagic...
1625 r = pakfire_file_classify_magic(file);
1626 if (r)
1627 goto ERROR;
1628
1629 // Check if the file is an ELF file
1630 r = pakfire_file_classify_elf(file);
1631 if (r)
1632 goto ERROR;
1633 }
1634 }
1635
1636 return file->class;
1637
1638 ERROR:
1639 // Reset the class
1640 file->class = PAKFIRE_FILE_UNKNOWN;
1641
1642 return r;
1643 }
1644
1645 int pakfire_file_matches_class(struct pakfire_file* file, const int class) {
1646 return pakfire_file_classify(file) & class;
1647 }
1648
1649 /*
1650 This function tries to remove the file after it has been packaged.
1651
1652 It will try to delete any parent directories as well and ignore if directories
1653 cannot be deleted because they might contain other files
1654 */
1655 int pakfire_file_cleanup(struct pakfire_file* file, int flags) {
1656 char path[PATH_MAX];
1657
1658 // Try removing the file
1659 int r = pakfire_file_remove(file);
1660 if (r)
1661 return r;
1662
1663 // Try to tidy up afterwards
1664 if (flags & PAKFIRE_FILE_CLEANUP_TIDY) {
1665 // Create a working copy of abspath
1666 r = pakfire_string_set(path, file->abspath);
1667 if (r)
1668 return r;
1669
1670 // See how many levels this file has
1671 int levels = pakfire_file_levels(file);
1672
1673 // Walk all the way up and remove all parent directories if possible
1674 while (--levels) {
1675 dirname(path);
1676
1677 // Break if path is suddenly empty
1678 if (!*path)
1679 break;
1680
1681 DEBUG(file->pakfire, "Trying to remove parent directory %s\n", path);
1682
1683 r = rmdir(path);
1684
1685 // Break on any error
1686 if (r)
1687 break;
1688 }
1689 }
1690
1691 return 0;
1692 }
1693
1694 static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat* st) {
1695 const mode_t type = pakfire_file_get_type(file);
1696
1697 // Did the type change?
1698 if (type != (st->st_mode & S_IFMT)) {
1699 file->verify_status |= PAKFIRE_FILE_TYPE_CHANGED;
1700
1701 DEBUG(file->pakfire, "%s: File Type changed\n", file->path);
1702 }
1703
1704 const mode_t perms = pakfire_file_get_perms(file);
1705
1706 // Check permissions
1707 if (perms != (st->st_mode & 0777)) {
1708 file->verify_status |= PAKFIRE_FILE_PERMISSIONS_CHANGED;
1709
1710 DEBUG(file->pakfire, "%s: Permissions changed\n", file->path);
1711 }
1712
1713 #if 0
1714 // XXX This does not check what it is supposed to check
1715
1716 // Check if device node changed
1717 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
1718 const dev_t dev = pakfire_file_get_dev(file);
1719
1720 if (dev != st->st_dev) {
1721 file->verify_status |= PAKFIRE_FILE_DEV_CHANGED;
1722
1723 DEBUG(file->pakfire, "%s: Device Node changed\n", file->path);
1724 }
1725 }
1726 #endif
1727
1728 return 0;
1729 }
1730
1731 static int pakfire_file_verify_size(struct pakfire_file* file, const struct stat* st) {
1732 // Nothing to do if size matches
1733 if (file->st.st_size == st->st_size)
1734 return 0;
1735
1736 // Size differs
1737 file->verify_status |= PAKFIRE_FILE_SIZE_CHANGED;
1738
1739 DEBUG(file->pakfire, "%s: Filesize differs (expected %zu, got %zu byte(s))\n",
1740 file->path, file->st.st_size, st->st_size);
1741
1742 return 0;
1743 }
1744
1745 static int pakfire_file_verify_ownership(struct pakfire_file* file, const struct stat* st) {
1746 // Fetch UID/GID
1747 #if 0
1748 const uid_t uid = pakfire_unmap_id(file->pakfire, st->st_uid);
1749 const gid_t gid = pakfire_unmap_id(file->pakfire, st->st_gid);
1750 #else
1751 const uid_t uid = st->st_uid;
1752 const gid_t gid = st->st_gid;
1753 #endif
1754
1755 // Fetch owner & group
1756 struct passwd* owner = pakfire_getpwnam(file->pakfire, file->uname);
1757 struct group* group = pakfire_getgrnam(file->pakfire, file->gname);
1758
1759 // Check if owner matches
1760 if (!owner || owner->pw_uid != uid) {
1761 file->verify_status |= PAKFIRE_FILE_OWNER_CHANGED;
1762
1763 DEBUG(file->pakfire, "%s: Owner differs\n", file->path);
1764 }
1765
1766 // Check if group matches
1767 if (!group || group->gr_gid != gid) {
1768 file->verify_status |= PAKFIRE_FILE_GROUP_CHANGED;
1769
1770 DEBUG(file->pakfire, "%s: Group differs\n", file->path);
1771 }
1772
1773 return 0;
1774 }
1775
1776 static int pakfire_file_verify_timestamps(struct pakfire_file* file, const struct stat* st) {
1777 // Check creation time
1778 if (file->st.st_ctime != st->st_ctime) {
1779 file->verify_status |= PAKFIRE_FILE_CTIME_CHANGED;
1780
1781 DEBUG(file->pakfire, "%s: Creation time changed\n", file->path);
1782 }
1783
1784 // Check modification time
1785 if (file->st.st_mtime != st->st_mtime) {
1786 file->verify_status |= PAKFIRE_FILE_MTIME_CHANGED;
1787
1788 DEBUG(file->pakfire, "%s: Modification time changed\n", file->path);
1789 }
1790
1791 return 0;
1792 }
1793
1794 static int pakfire_file_verify_payload(struct pakfire_file* file, const struct stat* st) {
1795 int r;
1796
1797 struct pakfire_digests computed_digests;
1798 int digest_types = PAKFIRE_DIGEST_UNDEFINED;
1799
1800 // Nothing to do for anything that isn't a regular file
1801 if (!S_ISREG(st->st_mode))
1802 return 0;
1803
1804 // Fast-path if size changed. The payload will have changed, too
1805 if (file->verify_status & PAKFIRE_FILE_SIZE_CHANGED) {
1806 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
1807 return 0;
1808 }
1809
1810 // Check if this file has any digests at all
1811 digest_types = pakfire_digest_has_any(&file->digests);
1812
1813 if (!digest_types) {
1814 ERROR(file->pakfire, "%s: No digests available\n", file->path);
1815 return 0;
1816 }
1817
1818 // Compute digests
1819 r = __pakfire_file_compute_digests(file, &computed_digests, digest_types);
1820 if (r)
1821 goto ERROR;
1822
1823 // Compare digests
1824 r = pakfire_digests_compare(file->pakfire, &file->digests, &computed_digests, digest_types);
1825 if (r) {
1826 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
1827
1828 DEBUG(file->pakfire, "%s: Digest(s) do not match\n", file->path);
1829 }
1830
1831 ERROR:
1832 return r;
1833 }
1834
1835 /*
1836 Verify the file - i.e. does the metadata match what is on disk?
1837 */
1838 int pakfire_file_verify(struct pakfire_file* file, int* status) {
1839 struct stat st;
1840 int r;
1841
1842 DEBUG(file->pakfire, "Verifying %s...\n", file->path);
1843
1844 // stat() the file
1845 r = lstat(file->abspath, &st);
1846 if (r) {
1847 // File does not exist
1848 if (errno == ENOENT) {
1849 file->verify_status |= PAKFIRE_FILE_NOENT;
1850 return 1;
1851 }
1852
1853 // Raise any other errors from stat()
1854 return r;
1855 }
1856
1857 // Verify mode
1858 r = pakfire_file_verify_mode(file, &st);
1859 if (r)
1860 return r;
1861
1862 // Verify size
1863 r = pakfire_file_verify_size(file, &st);
1864 if (r)
1865 return r;
1866
1867 // Verify ownership
1868 r = pakfire_file_verify_ownership(file, &st);
1869 if (r)
1870 return r;
1871
1872 // Verify timestamps
1873 r = pakfire_file_verify_timestamps(file, &st);
1874 if (r)
1875 return r;
1876
1877 // Verify payload
1878 r = pakfire_file_verify_payload(file, &st);
1879 if (r)
1880 return r;
1881
1882 return 0;
1883 }
1884
1885 PAKFIRE_EXPORT int pakfire_file_matches(struct pakfire_file* file, const char* pattern) {
1886 int r;
1887
1888 // Don't match on no pattern
1889 if (!pattern)
1890 return 0;
1891
1892 // Check if the pattern matches
1893 r = fnmatch(pattern, file->path, 0);
1894 switch (r) {
1895 // Match
1896 case 0:
1897 return 1;
1898
1899 // No Match
1900 case FNM_NOMATCH:
1901 return 0;
1902
1903 default:
1904 return -1;
1905 }
1906 }
1907
1908 /*
1909 ELF Stuff
1910 */
1911
1912 static int pakfire_file_open_elf(struct pakfire_file* file,
1913 int (*callback)(struct pakfire_file* file, Elf* elf, void* data), void* data) {
1914 FILE* f = NULL;
1915 Elf* elf = NULL;
1916 int r;
1917
1918 // Don't run this for non-ELF files
1919 if (!pakfire_file_matches_class(file, PAKFIRE_FILE_ELF)) {
1920 errno = EINVAL;
1921 return 1;
1922 }
1923
1924 // Setup libelf
1925 r = setup_libelf(file->pakfire);
1926 if (r)
1927 return r;
1928
1929 // Open the file
1930 f = fopen(file->abspath, "r");
1931 if (!f) {
1932 ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
1933 return 1;
1934 }
1935
1936 // Parse the ELF header
1937 elf = elf_begin(fileno(f), ELF_C_READ, NULL);
1938 if (!elf) {
1939 ERROR(file->pakfire, "Could not open ELF file: %s\n", elf_errmsg(-1));
1940 r = 1;
1941 goto ERROR;
1942 }
1943
1944 // Check if this is an ELF file
1945 switch (elf_kind(elf)) {
1946 case ELF_K_ELF:
1947 break;
1948
1949 default:
1950 ERROR(file->pakfire, "%s is not an ELF object\n", file->path);
1951 r = 1;
1952 goto ERROR;
1953 }
1954
1955 // Call the callback
1956 r = callback(file, elf, data);
1957
1958 ERROR:
1959 if (elf)
1960 elf_end(elf);
1961 if (f)
1962 fclose(f);
1963
1964 return r;
1965 }
1966
1967 static int pakfire_file_get_elf_section(struct pakfire_file* file,
1968 Elf* elf, const Elf64_Word type, Elf_Scn** section, GElf_Shdr* header, Elf_Data** data) {
1969 Elf_Scn* s = NULL;
1970
1971 GElf_Shdr shdr;
1972
1973 // Walk through all sections
1974 for (;;) {
1975 s = elf_nextscn(elf, s);
1976 if (!s)
1977 break;
1978
1979 // Fetch the section header
1980 gelf_getshdr(s, &shdr);
1981
1982 // Return any matching sections
1983 if (shdr.sh_type == type) {
1984 *section = s;
1985
1986 // Send header if requested
1987 if (header)
1988 gelf_getshdr(s, header);
1989
1990 // Send data if requested
1991 if (data)
1992 *data = elf_getdata(s, NULL);
1993
1994 return 0;
1995 }
1996 }
1997
1998 // No section found
1999 return 1;
2000 }
2001
2002 static int __pakfire_file_get_elf_type(struct pakfire_file* file, Elf* elf, void* data) {
2003 int* type = (int*)data;
2004 GElf_Ehdr ehdr;
2005
2006 // Fetch the ELF header
2007 if (!gelf_getehdr(elf, &ehdr)) {
2008 ERROR(file->pakfire, "Could not parse ELF header: %s\n", elf_errmsg(-1));
2009 return 1;
2010 }
2011
2012 // Store the type
2013 *type = ehdr.e_type;
2014
2015 return 0;
2016 }
2017
2018 static int pakfire_file_get_elf_type(struct pakfire_file* file) {
2019 int type = ET_NONE;
2020 int r;
2021
2022 r = pakfire_file_open_elf(file, __pakfire_file_get_elf_type, &type);
2023 if (r)
2024 return -1;
2025
2026 return type;
2027 }
2028
2029 static int pakfire_file_elf_dyn_walk(struct pakfire_file* file, Elf* elf,
2030 int (*callback)(struct pakfire_file* file,
2031 Elf* elf, const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data),
2032 void* data) {
2033 Elf_Scn* dynamic = NULL;
2034 GElf_Shdr shdr;
2035 Elf_Data* elf_data = NULL;
2036 GElf_Dyn dyn;
2037 int r;
2038
2039 // Find the dynamic linking information
2040 r = pakfire_file_get_elf_section(file, elf, SHT_DYNAMIC, &dynamic, &shdr, &elf_data);
2041 if (r) {
2042 ERROR(file->pakfire, "%s does not have a dynamic section\n", file->path);
2043 return 1;
2044 }
2045
2046 // Walk through all entries...
2047 for (unsigned int i = 0; ; i++) {
2048 // Fetch the next entry
2049 if (!gelf_getdyn(elf_data, i, &dyn))
2050 break;
2051
2052 // Call the callback
2053 r = callback(file, elf, &shdr, &dyn, data);
2054 if (r)
2055 return r;
2056 }
2057
2058 return 0;
2059 }
2060
2061 static int __pakfire_file_check_debuginfo(struct pakfire_file* file, Elf* elf, void* data) {
2062 Elf_Scn* symtab = NULL;
2063 int r;
2064
2065 // Fetch the symbol table
2066 r = pakfire_file_get_elf_section(file, elf, SHT_SYMTAB, &symtab, NULL, NULL);
2067
2068 // Not found
2069 if (r) {
2070 DEBUG(file->pakfire, "%s has no debug sections\n", file->path);
2071
2072 // Store the result
2073 file->issues |= PAKFIRE_FILE_MISSING_DEBUGINFO;
2074 }
2075
2076 return 0;
2077 }
2078
2079 static int pakfire_file_check_debuginfo(struct pakfire_file* file) {
2080 switch (pakfire_file_get_elf_type(file)) {
2081 // Do not check Relocatable Objects
2082 case ET_REL:
2083 return 0;
2084
2085 // Check everything else
2086 default:
2087 break;
2088 }
2089
2090 return pakfire_file_open_elf(file, __pakfire_file_check_debuginfo, NULL);
2091 }
2092
2093 static int __pakfire_file_check_ssp(
2094 struct pakfire_file* file, Elf* elf, void* data) {
2095 Elf_Scn* symtab = NULL;
2096 GElf_Shdr shdr;
2097 Elf_Data* elf_data = NULL;
2098 GElf_Sym symbol;
2099 const char* name = NULL;
2100 int r;
2101
2102 // Fetch the symbol table
2103 r = pakfire_file_get_elf_section(file, elf, SHT_SYMTAB, &symtab, &shdr, &elf_data);
2104 if (r) {
2105 ERROR(file->pakfire, "%s has no symbol table\n", file->path);
2106 return 1;
2107 }
2108
2109 // Count any global functions
2110 size_t counter = 0;
2111
2112 // Walk through all symbols
2113 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
2114 gelf_getsym(elf_data, i, &symbol);
2115
2116 // Fetch the symbol name
2117 name = elf_strptr(elf, shdr.sh_link, symbol.st_name);
2118
2119 // Skip empty section names
2120 if (!name || !*name)
2121 continue;
2122
2123 // Exit if there is a symbol called "__stack_chk_fail"
2124 if (pakfire_string_startswith(name, "__stack_chk_fail"))
2125 return 0;
2126
2127 // Count any global functions
2128 if ((ELF64_ST_BIND(symbol.st_info) == STB_GLOBAL) &&
2129 (ELF64_ST_TYPE(symbol.st_info) == STT_FUNC))
2130 counter++;
2131 }
2132
2133 // We do not perform the check for libraries that do not contain any functions.
2134 // Some packages use shared libraries to provide data.
2135 if (!counter) {
2136 DEBUG(file->pakfire, "%s: File has no functions. Skipping SSP check.\n", file->path);
2137 return 0;
2138 }
2139
2140 // The file does not seem to have SSP enabled
2141 file->issues |= PAKFIRE_FILE_MISSING_SSP;
2142
2143 return 0;
2144 }
2145
2146 static int pakfire_file_check_ssp(struct pakfire_file* file) {
2147 // This check will be skipped for these files
2148 static const char* whitelist[] = {
2149 "/usr/lib64/libgcc_s.so.*",
2150 "/usr/lib64/libmvec.so.*",
2151 NULL,
2152 };
2153
2154 // Do not perform this check for runtime linkers
2155 if (pakfire_file_matches_class(file, PAKFIRE_FILE_RUNTIME_LINKER))
2156 return 0;
2157
2158 // We cannot perform this check if we don't have debuginfo
2159 if (file->issues & PAKFIRE_FILE_MISSING_DEBUGINFO)
2160 return 0;
2161
2162 // Check if this file is whitelisted
2163 for (const char** path = whitelist; *path; path++) {
2164 if (pakfire_file_matches(file, *path)) {
2165 DEBUG(file->pakfire, "Skipping SSP check for whitelisted file %s\n",
2166 pakfire_file_get_path(file));
2167 return 0;
2168 }
2169 }
2170
2171 return pakfire_file_open_elf(file, __pakfire_file_check_ssp, NULL);
2172 }
2173
2174 static int pakfire_file_check_pie(struct pakfire_file* file) {
2175 switch (pakfire_file_get_elf_type(file)) {
2176 // Shared Object files are good
2177 case ET_DYN:
2178 break;
2179
2180 // Everything else is bad
2181 default:
2182 file->issues |= PAKFIRE_FILE_MISSING_PIE;
2183 break;
2184 }
2185
2186 return 0;
2187 }
2188
2189 static int __pakfire_file_check_execstack(
2190 struct pakfire_file* file, Elf* elf, void* data) {
2191 GElf_Phdr phdr;
2192 int r;
2193
2194 size_t phnum = 0;
2195
2196 // Fetch the total numbers of program headers
2197 r = elf_getphdrnum(elf, &phnum);
2198 if (r) {
2199 ERROR(file->pakfire, "Could not fetch number of program headers: %s\n",
2200 elf_errmsg(-1));
2201 return 1;
2202 }
2203
2204 // Walk through all program headers
2205 for (unsigned int i = 0; i < phnum; i++) {
2206 if (!gelf_getphdr(elf, i, &phdr)) {
2207 ERROR(file->pakfire, "Could not parse program header: %s\n", elf_errmsg(-1));
2208 return 1;
2209 }
2210
2211 switch (phdr.p_type) {
2212 case PT_GNU_STACK:
2213 DEBUG(file->pakfire,
2214 "%s: GNU_STACK flags: %c%c%c\n",
2215 file->path,
2216 (phdr.p_flags & PF_R) ? 'R' : '-',
2217 (phdr.p_flags & PF_W) ? 'W' : '-',
2218 (phdr.p_flags & PF_X) ? 'X' : '-'
2219 );
2220
2221 // The stack cannot be writable and executable
2222 if ((phdr.p_flags & PF_W) && (phdr.p_flags & PF_X))
2223 file->issues |= PAKFIRE_FILE_EXECSTACK;
2224
2225 // Done
2226 return 0;
2227
2228 default:
2229 break;
2230 }
2231 }
2232
2233 return 0;
2234 }
2235
2236 static int pakfire_file_check_execstack(struct pakfire_file* file) {
2237 return pakfire_file_open_elf(file, __pakfire_file_check_execstack, NULL);
2238 }
2239
2240 static int __pakfire_file_process_bind_now(struct pakfire_file* file,
2241 Elf* elf, const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
2242 int* has_bind_now = (int*)data;
2243
2244 switch (dyn->d_tag) {
2245 case DT_BIND_NOW:
2246 *has_bind_now = 1;
2247 break;
2248
2249 case DT_FLAGS:
2250 if (dyn->d_un.d_val & DF_BIND_NOW)
2251 *has_bind_now = 1;
2252 break;
2253
2254 case DT_FLAGS_1:
2255 if (dyn->d_un.d_val & DF_1_NOW)
2256 *has_bind_now = 1;
2257 break;
2258
2259 default:
2260 break;
2261 }
2262
2263 return 0;
2264 }
2265
2266 static int __pakfire_file_check_relro(
2267 struct pakfire_file* file, Elf* elf, void* data) {
2268 int has_bind_now = 0;
2269 GElf_Phdr phdr;
2270 int r;
2271
2272 // Check if we have BIND_NOW
2273 r = pakfire_file_elf_dyn_walk(file, elf,
2274 __pakfire_file_process_bind_now, &has_bind_now);
2275 if (r)
2276 return r;
2277
2278 // We are not fully RELRO
2279 if (!has_bind_now) {
2280 file->issues |= PAKFIRE_FILE_NO_RELRO;
2281
2282 return 0;
2283 }
2284
2285 // Walk through all program headers
2286 for (unsigned int i = 0;; i++) {
2287 if (!gelf_getphdr(elf, i, &phdr))
2288 break;
2289
2290 switch (phdr.p_type) {
2291 case PT_GNU_RELRO:
2292 return 0;
2293
2294 default:
2295 break;
2296 }
2297 }
2298
2299 // This file does not seem to have PT_GNU_RELRO set
2300 file->issues |= PAKFIRE_FILE_NO_RELRO;
2301
2302 return 0;
2303 }
2304
2305 static int pakfire_file_check_relro(struct pakfire_file* file) {
2306 return pakfire_file_open_elf(file, __pakfire_file_check_relro, NULL);
2307 }
2308
2309 /*
2310 RPATH/RUNPATH
2311 */
2312 static int __pakfire_file_process_runpath(struct pakfire_file* file,
2313 Elf* elf, const GElf_Shdr* shdr, const GElf_Dyn* dyn, void* data) {
2314 const char* value = NULL;
2315 const char* runpath = NULL;
2316 char buffer[PATH_MAX];
2317 char* p = NULL;
2318 int r;
2319
2320 switch (dyn->d_tag) {
2321 case DT_RUNPATH:
2322 case DT_RPATH:
2323 // Fetch the value
2324 value = elf_strptr(elf, shdr->sh_link, dyn->d_un.d_val);
2325 if (!value)
2326 return 1;
2327
2328 DEBUG(file->pakfire, "%s has a RUNPATH: %s\n", file->path, value);
2329
2330 // Copy the value into a buffer we can modify
2331 r = pakfire_string_set(buffer, value);
2332 if (r)
2333 return r;
2334
2335 // Split the value by :
2336 runpath = strtok_r(buffer, ":", &p);
2337
2338 // Iterate over all elements
2339 while (runpath) {
2340 ERROR(file->pakfire, "Checking RUNPATH %s\n", runpath);
2341
2342 // We do not allow any relative RUNPATHs
2343 if (pakfire_path_match(runpath, "**/../**"))
2344 goto RUNPATH_DENIED;
2345
2346 // We allow /usr/lib64 as libtool seems to link it in quite a lot
2347 if (pakfire_path_match("/usr/lib64", runpath))
2348 goto RUNPATH_PERMITTED;
2349
2350 // We allow any subdirectories of /usr/lib64
2351 if (pakfire_path_match( "/usr/lib64/**", runpath))
2352 goto RUNPATH_PERMITTED;
2353
2354 RUNPATH_DENIED:
2355 // If we make it here, this check has failed
2356 file->issues |= PAKFIRE_FILE_HAS_RUNPATH;
2357 break;
2358
2359 RUNPATH_PERMITTED:
2360 // Move on to the next RUNPATH
2361 runpath = strtok_r(NULL, ":", &p);
2362 }
2363
2364 default:
2365 break;
2366 }
2367
2368 return 0;
2369 }
2370
2371 static int __pakfire_file_check_runpath(struct pakfire_file* file, Elf* elf, void* data) {
2372 return pakfire_file_elf_dyn_walk(file, elf, __pakfire_file_process_runpath, data);
2373 }
2374
2375 static int pakfire_file_check_runpath(struct pakfire_file* file) {
2376 return pakfire_file_open_elf(file, __pakfire_file_check_runpath, NULL);
2377 }
2378
2379 static int pakfire_file_check_capabilities(struct pakfire_file* file) {
2380 // Files cannot have capabilities but not be executable
2381 if (!pakfire_file_is_executable(file) && pakfire_file_has_caps(file))
2382 file->issues |= PAKFIRE_FILE_INVALID_CAPS;
2383
2384 return 0;
2385 }
2386
2387
2388 int pakfire_file_check(struct pakfire_file* file, int* issues) {
2389 int r;
2390
2391 // Return previous result if this has been run before
2392 if (!file->check_done) {
2393 // Perform FHS check
2394 r = pakfire_fhs_check_file(file->pakfire, file);
2395 if (r)
2396 file->issues |= PAKFIRE_FILE_FHS_ERROR;
2397
2398 // Perform capability check
2399 r = pakfire_file_check_capabilities(file);
2400 if (r)
2401 return r;
2402
2403 // Do not perform the following checks on firmware
2404 if (pakfire_file_matches_class(file, PAKFIRE_FILE_FIRMWARE))
2405 goto DONE;
2406
2407 // Run these checks only for ELF files
2408 if (pakfire_file_matches_class(file, PAKFIRE_FILE_ELF)) {
2409 switch (pakfire_file_get_elf_type(file)) {
2410 // Do not check Relocatable Objects
2411 case ET_REL:
2412 goto DONE;
2413
2414 // Check everything else
2415 default:
2416 break;
2417 }
2418
2419 // Check if the file has debug info
2420 r = pakfire_file_check_debuginfo(file);
2421 if (r)
2422 return r;
2423
2424 // Check for SSP
2425 r = pakfire_file_check_ssp(file);
2426 if (r)
2427 return r;
2428
2429 // Check for PIE
2430 r = pakfire_file_check_pie(file);
2431 if (r)
2432 return r;
2433
2434 // Check for executable stacks
2435 r = pakfire_file_check_execstack(file);
2436 if (r)
2437 return r;
2438
2439 // Check for RELRO
2440 r = pakfire_file_check_relro(file);
2441 if (r)
2442 return r;
2443
2444 // Check for RUNPATH
2445 r = pakfire_file_check_runpath(file);
2446 if (r)
2447 return r;
2448 }
2449
2450 DONE:
2451 // All checks done
2452 file->check_done = 1;
2453 }
2454
2455 // Return any issues
2456 if (issues)
2457 *issues = file->issues;
2458
2459 return 0;
2460 }