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