1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2014 Pakfire development team #
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. #
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. #
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/>. #
19 #############################################################################*/
25 #include <linux/limits.h>
29 #include <sys/types.h>
32 #include <archive_entry.h>
36 #include <pakfire/constants.h>
37 #include <pakfire/digest.h>
38 #include <pakfire/fhs.h>
39 #include <pakfire/file.h>
40 #include <pakfire/logging.h>
41 #include <pakfire/pakfire.h>
42 #include <pakfire/private.h>
43 #include <pakfire/string.h>
44 #include <pakfire/util.h>
46 enum pakfire_file_verification_status
{
47 PAKFIRE_FILE_NOENT
= (1 << 0),
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),
54 PAKFIRE_FILE_CTIME_CHANGED
= (1 << 7),
55 PAKFIRE_FILE_MTIME_CHANGED
= (1 << 8),
56 PAKFIRE_FILE_PAYLOAD_CHANGED
= (1 << 9),
60 struct pakfire
* pakfire
;
66 // The absolute path in the file system
67 char abspath
[PATH_MAX
];
70 char uname
[LOGIN_NAME_MAX
];
71 char gname
[LOGIN_NAME_MAX
];
80 char hardlink
[PATH_MAX
];
81 char symlink
[PATH_MAX
];
84 struct pakfire_digests digests
;
87 char mimetype
[NAME_MAX
];
92 // Verification Status
99 #warning TODO capabilities, data
104 static int pakfire_file_from_archive_entry(struct pakfire_file
* file
, struct archive_entry
* entry
) {
106 const char* path
= NULL
;
107 const char* attr
= NULL
;
108 const void* value
= NULL
;
113 path
= archive_entry_sourcepath(entry
);
115 // Make path absolute
116 path
= pakfire_path_abspath(path
);
123 r
= pakfire_file_set_abspath(file
, path
);
125 ERROR(file
->pakfire
, "Could not set abspath: %m\n");
131 path
= archive_entry_pathname(entry
);
133 r
= pakfire_file_set_path(file
, path
);
135 ERROR(file
->pakfire
, "Could not set path: %m\n");
141 pakfire_file_set_hardlink(file
, archive_entry_hardlink(entry
));
142 pakfire_file_set_symlink(file
, archive_entry_symlink(entry
));
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
));
149 pakfire_file_set_size(file
, archive_entry_size(entry
));
152 pakfire_file_set_mode(file
, archive_entry_mode(entry
));
155 if (archive_entry_dev_is_set(entry
))
156 pakfire_file_set_dev(file
, archive_entry_dev(entry
));
159 pakfire_file_set_uname(file
, archive_entry_uname(entry
));
162 pakfire_file_set_gname(file
, archive_entry_gname(entry
));
165 pakfire_file_set_ctime(file
, archive_entry_ctime(entry
));
166 pakfire_file_set_mtime(file
, archive_entry_mtime(entry
));
168 // Reset iterating over extended attributes
169 archive_entry_xattr_reset(entry
);
171 // Read any extended attributes
172 while (archive_entry_xattr_next(entry
, &attr
, &value
, &size
) == ARCHIVE_OK
) {
174 if (strcmp(attr
, "PAKFIRE.config") == 0) {
175 r
= pakfire_file_set_flags(file
, PAKFIRE_FILE_CONFIG
);
180 } else if (strcmp(attr
, "PAKFIRE.mimetype") == 0) {
181 // Copy the value into a NULL-terminated buffer
182 r
= asprintf(&buffer
, "%.*s", (int)size
, (const char*)value
);
187 r
= pakfire_file_set_mimetype(file
, buffer
);
192 } else if (strcmp(attr
, "PAKFIRE.digests.sha3_512") == 0) {
193 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA3_512
, value
, size
);
198 } else if (strcmp(attr
, "PAKFIRE.digests.sha3_256") == 0) {
199 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA3_256
, value
, size
);
203 // Digest: BLAKE2b512
204 } else if (strcmp(attr
, "PAKFIRE.digests.blake2b512") == 0) {
205 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_BLAKE2B512
, value
, size
);
209 // Digest: BLAKE2s256
210 } else if (strcmp(attr
, "PAKFIRE.digests.blake2s256") == 0) {
211 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_BLAKE2S256
, value
, size
);
216 } else if (strcmp(attr
, "PAKFIRE.digests.sha2_512") == 0) {
217 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA2_512
, value
, size
);
222 } else if (strcmp(attr
, "PAKFIRE.digests.sha2_256") == 0) {
223 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA2_256
, value
, size
);
228 DEBUG(file
->pakfire
, "Received an unknown extended attribute: %s\n", attr
);
239 PAKFIRE_EXPORT
int pakfire_file_create(struct pakfire_file
** file
, struct pakfire
* pakfire
) {
240 struct pakfire_file
* f
= calloc(1, sizeof(*f
));
244 // Store reference to Pakfire
245 f
->pakfire
= pakfire_ref(pakfire
);
247 // Initialize reference counter
254 int 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
;
261 reader
= pakfire_make_archive_disk_reader(pakfire
, 0);
265 // Allocate a new archive entry
266 entry
= archive_entry_new();
271 archive_entry_copy_sourcepath(entry
, path
);
273 // Read all file attributes from disk
274 r
= archive_read_disk_entry_from_file(reader
, entry
, -1, NULL
);
276 ERROR(pakfire
, "Could not read from %s: %m\n", path
);
281 r
= pakfire_file_create_from_archive_entry(file
, pakfire
, entry
);
287 ERROR(pakfire
, "Could not create file from path %s: %m\n", path
);
289 archive_entry_free(entry
);
291 archive_read_free(reader
);
296 int pakfire_file_create_from_archive_entry(struct pakfire_file
** file
, struct pakfire
* pakfire
,
297 struct archive_entry
* entry
) {
298 int r
= pakfire_file_create(file
, pakfire
);
302 // Copy archive entry
303 r
= pakfire_file_from_archive_entry(*file
, entry
);
310 pakfire_file_unref(*file
);
316 struct archive_entry
* pakfire_file_archive_entry(struct pakfire_file
* file
, int digest_types
) {
317 const char* path
= NULL
;
320 struct archive_entry
* entry
= archive_entry_new();
322 ERROR(file
->pakfire
, "Could not allocate archive entry: %m\n");
327 archive_entry_copy_sourcepath(entry
, file
->abspath
);
330 path
= pakfire_file_get_path(file
);
331 if (path
&& *path
== '/') {
332 archive_entry_copy_pathname(entry
, path
+ 1);
337 archive_entry_set_hardlink(entry
, file
->hardlink
);
339 archive_entry_set_symlink(entry
, file
->symlink
);
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
));
346 archive_entry_set_size(entry
, pakfire_file_get_size(file
));
349 archive_entry_set_mode(entry
, pakfire_file_get_mode(file
));
352 archive_entry_set_uname(entry
, pakfire_file_get_uname(file
));
355 archive_entry_set_gname(entry
, pakfire_file_get_gname(file
));
358 archive_entry_set_ctime(entry
, pakfire_file_get_ctime(file
), 0);
359 archive_entry_set_mtime(entry
, pakfire_file_get_mtime(file
), 0);
362 if (pakfire_file_has_flag(file
, PAKFIRE_FILE_CONFIG
)) {
363 archive_entry_xattr_add_entry(entry
,
364 "PAKFIRE.config", "1", strlen("1"));
368 const char* mimetype
= pakfire_file_get_mimetype(file
);
370 archive_entry_xattr_add_entry(entry
,
371 "PAKFIRE.mimetype", mimetype
, strlen(mimetype
));
374 // Compute any required file digests
375 r
= pakfire_file_compute_digests(file
, digest_types
);
382 if ((digest_types
&& PAKFIRE_DIGEST_SHA3_512
)
383 && pakfire_digest_set(file
->digests
.sha3_512
))
384 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha3_512",
385 file
->digests
.sha3_512
, sizeof(file
->digests
.sha3_512
));
388 if ((digest_types
&& PAKFIRE_DIGEST_SHA3_256
) &&
389 pakfire_digest_set(file
->digests
.sha3_256
))
390 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha3_256",
391 file
->digests
.sha3_256
, sizeof(file
->digests
.sha3_256
));
394 if ((digest_types
&& PAKFIRE_DIGEST_BLAKE2B512
) &&
395 pakfire_digest_set(file
->digests
.blake2b512
))
396 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.blake2b512",
397 file
->digests
.blake2b512
, sizeof(file
->digests
.blake2b512
));
400 if ((digest_types
&& PAKFIRE_DIGEST_BLAKE2S256
) &&
401 pakfire_digest_set(file
->digests
.blake2s256
))
402 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.blake2s256",
403 file
->digests
.blake2s256
, sizeof(file
->digests
.blake2s256
));
406 if ((digest_types
&& PAKFIRE_DIGEST_SHA2_512
) &&
407 pakfire_digest_set(file
->digests
.sha2_512
))
408 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha2_512",
409 file
->digests
.sha2_512
, sizeof(file
->digests
.sha2_512
));
412 if ((digest_types
&& PAKFIRE_DIGEST_SHA2_512
) &&
413 pakfire_digest_set(file
->digests
.sha2_256
))
414 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha2_256",
415 file
->digests
.sha2_256
, sizeof(file
->digests
.sha2_256
));
421 archive_entry_free(entry
);
426 static void pakfire_file_free(struct pakfire_file
* file
) {
427 pakfire_unref(file
->pakfire
);
431 PAKFIRE_EXPORT
struct pakfire_file
* pakfire_file_ref(struct pakfire_file
* file
) {
437 PAKFIRE_EXPORT
struct pakfire_file
* pakfire_file_unref(struct pakfire_file
* file
) {
438 if (--file
->nrefs
> 0)
441 pakfire_file_free(file
);
449 int pakfire_file_has_flag(struct pakfire_file
* file
, int flag
) {
450 return file
->flags
& flag
;
453 int pakfire_file_set_flags(struct pakfire_file
* file
, int flag
) {
459 #define pakfire_file_strmode(file, buffer) \
460 __pakfire_file_strmode(file, buffer, sizeof(buffer))
462 static int __pakfire_file_strmode(struct pakfire_file
* file
, char* s
, const size_t length
) {
465 static const mode_t permbits
[] = {
477 const mode_t mode
= pakfire_file_get_mode(file
);
478 const mode_t type
= pakfire_file_get_type(file
);
480 // Set some default string
481 r
= __pakfire_string_set(s
, length
, "?rwxrwxrwx ");
515 if (*file
->hardlink
) {
521 for (unsigned int i
= 0; i
< 9; i
++) {
522 if (mode
& permbits
[i
])
528 if (mode
& S_ISUID
) {
535 if (mode
& S_ISGID
) {
542 if (mode
& S_ISVTX
) {
557 char* pakfire_file_dump(struct pakfire_file
* file
, int flags
) {
565 if (flags
& PAKFIRE_FILE_DUMP_MODE
) {
566 r
= pakfire_file_strmode(file
, mode
);
570 r
= asprintf(&buffer
, "%s %s", buffer
, mode
);
576 if (flags
& PAKFIRE_FILE_DUMP_OWNERSHIP
) {
577 r
= asprintf(&buffer
, "%s %s/%s", buffer
, file
->uname
, file
->gname
);
583 if (flags
& PAKFIRE_FILE_DUMP_SIZE
) {
584 r
= asprintf(&buffer
, "%s %8zu", buffer
, file
->st
.st_size
);
590 if (flags
& PAKFIRE_FILE_DUMP_TIME
) {
591 r
= pakfire_strftime(time
, "%Y-%m-%d %H:%M", file
->st
.st_ctime
);
595 r
= asprintf(&buffer
, "%s %s", buffer
, time
);
601 r
= asprintf(&buffer
, "%s %s", buffer
, file
->path
);
605 // Append symlink target
606 if (flags
& PAKFIRE_FILE_DUMP_LINK_TARGETS
) {
607 switch (pakfire_file_get_type(file
)) {
609 r
= asprintf(&buffer
, "%s -> %s", buffer
, file
->symlink
);
619 if (flags
& PAKFIRE_FILE_DUMP_ISSUES
) {
620 if (file
->issues
& PAKFIRE_FILE_FHS_ERROR
) {
621 r
= asprintf(&buffer
, "%s [FHS-ERROR]", buffer
);
626 if (file
->issues
& PAKFIRE_FILE_MISSING_DEBUGINFO
) {
627 r
= asprintf(&buffer
, "%s [MISSING-DEBUGINFO]", buffer
);
632 // Stack-smashing Protection
633 if (file
->issues
& PAKFIRE_FILE_MISSING_SSP
) {
634 r
= asprintf(&buffer
, "%s [MISSING-SSP]", buffer
);
639 // Position-independent Executable
640 if (file
->issues
& PAKFIRE_FILE_MISSING_PIE
) {
641 r
= asprintf(&buffer
, "%s [MISSING-PIE]", buffer
);
647 if (file
->issues
& PAKFIRE_FILE_EXECSTACK
) {
648 r
= asprintf(&buffer
, "%s [EXECSTACK]", buffer
);
653 // Not Partially RELRO
654 if (file
->issues
& PAKFIRE_FILE_NO_PARTIALLY_RELRO
) {
655 r
= asprintf(&buffer
, "%s [NO-PART-RELRO]", buffer
);
661 if (file
->issues
& PAKFIRE_FILE_HAS_RUNPATH
) {
662 r
= asprintf(&buffer
, "%s [HAS-RUNPATH]", buffer
);
677 PAKFIRE_EXPORT
int pakfire_file_cmp(struct pakfire_file
* file1
, struct pakfire_file
* file2
) {
678 const char* path1
= pakfire_file_get_path(file1
);
679 const char* path2
= pakfire_file_get_path(file2
);
681 return strcmp(path1
, path2
);
684 const char* pakfire_file_get_abspath(struct pakfire_file
* file
) {
685 return file
->abspath
;
688 int pakfire_file_set_abspath(struct pakfire_file
* file
, const char* path
) {
691 // Check if path is set and absolute
692 if (!path
|| *path
!= '/') {
698 r
= pakfire_string_set(file
->abspath
, path
);
702 // Store path if it isn't set, yet
704 r
= pakfire_file_set_path(file
, path
);
712 ERROR(file
->pakfire
, "Could not set abspath '%s': %m\n", path
);
716 PAKFIRE_EXPORT
const char* pakfire_file_get_path(struct pakfire_file
* file
) {
720 PAKFIRE_EXPORT
int pakfire_file_set_path(struct pakfire_file
* file
, const char* path
) {
723 // Check if path is set
729 // Strip any leading dots from paths
730 if (pakfire_string_startswith(path
, "./"))
734 // Just store the path if it is absolute
736 r
= pakfire_string_set(file
->path
, path
);
741 // Handle relative paths
743 r
= pakfire_string_format(file
->path
, "/%s", path
);
749 // Set abspath if it isn't set, yet
750 if (!*file
->abspath
) {
751 r
= pakfire_file_set_abspath(file
, file
->path
);
759 ERROR(file
->pakfire
, "Could not set path '%s': %m\n", path
);
763 PAKFIRE_EXPORT
const char* pakfire_file_get_hardlink(struct pakfire_file
* file
) {
764 if (!*file
->hardlink
)
767 return file
->hardlink
;
770 PAKFIRE_EXPORT
void pakfire_file_set_hardlink(struct pakfire_file
* file
, const char* link
) {
771 pakfire_string_set(file
->hardlink
, link
);
774 PAKFIRE_EXPORT
const char* pakfire_file_get_symlink(struct pakfire_file
* file
) {
778 return file
->symlink
;
781 PAKFIRE_EXPORT
void pakfire_file_set_symlink(struct pakfire_file
* file
, const char* link
) {
782 pakfire_string_set(file
->symlink
, link
);
785 PAKFIRE_EXPORT nlink_t
pakfire_file_get_nlink(struct pakfire_file
* file
) {
786 return file
->st
.st_nlink
;
789 PAKFIRE_EXPORT
void pakfire_file_set_nlink(struct pakfire_file
* file
, const nlink_t nlink
) {
790 file
->st
.st_nlink
= nlink
;
793 PAKFIRE_EXPORT ino_t
pakfire_file_get_inode(struct pakfire_file
* file
) {
794 return file
->st
.st_ino
;
797 PAKFIRE_EXPORT
void pakfire_file_set_inode(struct pakfire_file
* file
, const ino_t ino
) {
798 file
->st
.st_ino
= ino
;
801 PAKFIRE_EXPORT dev_t
pakfire_file_get_dev(struct pakfire_file
* file
) {
802 return file
->st
.st_dev
;
805 PAKFIRE_EXPORT
void pakfire_file_set_dev(struct pakfire_file
* file
, const dev_t dev
) {
806 file
->st
.st_dev
= dev
;
809 PAKFIRE_EXPORT
int pakfire_file_get_type(struct pakfire_file
* file
) {
810 return file
->st
.st_mode
& S_IFMT
;
813 PAKFIRE_EXPORT off_t
pakfire_file_get_size(struct pakfire_file
* file
) {
814 return file
->st
.st_size
;
817 PAKFIRE_EXPORT
void pakfire_file_set_size(struct pakfire_file
* file
, off_t size
) {
818 file
->st
.st_size
= size
;
821 PAKFIRE_EXPORT
const char* pakfire_file_get_uname(struct pakfire_file
* file
) {
825 PAKFIRE_EXPORT
int pakfire_file_set_uname(struct pakfire_file
* file
, const char* uname
) {
826 return pakfire_string_set(file
->uname
, uname
);
829 PAKFIRE_EXPORT
const char* pakfire_file_get_gname(struct pakfire_file
* file
) {
833 PAKFIRE_EXPORT
int pakfire_file_set_gname(struct pakfire_file
* file
, const char* gname
) {
834 return pakfire_string_set(file
->gname
, gname
);
837 PAKFIRE_EXPORT mode_t
pakfire_file_get_mode(struct pakfire_file
* file
) {
838 return file
->st
.st_mode
;
841 PAKFIRE_EXPORT
void pakfire_file_set_mode(struct pakfire_file
* file
, mode_t mode
) {
842 file
->st
.st_mode
= mode
;
845 PAKFIRE_EXPORT mode_t
pakfire_file_get_perms(struct pakfire_file
* file
) {
846 return file
->st
.st_mode
& ~S_IFMT
;
849 PAKFIRE_EXPORT
void pakfire_file_set_perms(struct pakfire_file
* file
, const mode_t perms
) {
850 // Clear any previous permissions
851 file
->st
.st_mode
&= S_IFMT
;
853 // Set new bits (with format cleared)
854 file
->st
.st_mode
|= ~S_IFMT
& perms
;
857 PAKFIRE_EXPORT
time_t pakfire_file_get_ctime(struct pakfire_file
* file
) {
858 return file
->st
.st_ctime
;
861 PAKFIRE_EXPORT
void pakfire_file_set_ctime(struct pakfire_file
* file
, time_t time
) {
862 file
->st
.st_ctime
= time
;
865 PAKFIRE_EXPORT
time_t pakfire_file_get_mtime(struct pakfire_file
* file
) {
866 return file
->st
.st_mtime
;
869 PAKFIRE_EXPORT
void pakfire_file_set_mtime(struct pakfire_file
* file
, time_t time
) {
870 file
->st
.st_mtime
= time
;
873 PAKFIRE_EXPORT
const unsigned char* pakfire_file_get_digest(
874 struct pakfire_file
* file
, const enum pakfire_digest_types type
, size_t* length
) {
877 case PAKFIRE_DIGEST_SHA3_512
:
878 if (!pakfire_digest_set(file
->digests
.sha3_512
))
882 *length
= sizeof(file
->digests
.sha3_512
);
884 return file
->digests
.sha3_512
;
886 case PAKFIRE_DIGEST_SHA3_256
:
887 if (!pakfire_digest_set(file
->digests
.sha3_256
))
891 *length
= sizeof(file
->digests
.sha3_256
);
893 return file
->digests
.sha3_256
;
895 case PAKFIRE_DIGEST_BLAKE2B512
:
896 if (!pakfire_digest_set(file
->digests
.blake2b512
))
900 *length
= sizeof(file
->digests
.blake2b512
);
902 return file
->digests
.blake2b512
;
904 case PAKFIRE_DIGEST_BLAKE2S256
:
905 if (!pakfire_digest_set(file
->digests
.blake2s256
))
909 *length
= sizeof(file
->digests
.blake2s256
);
911 return file
->digests
.blake2s256
;
913 case PAKFIRE_DIGEST_SHA2_512
:
914 if (!pakfire_digest_set(file
->digests
.sha2_512
))
918 *length
= sizeof(file
->digests
.sha2_512
);
920 return file
->digests
.sha2_512
;
922 case PAKFIRE_DIGEST_SHA2_256
:
923 if (!pakfire_digest_set(file
->digests
.sha2_256
))
927 *length
= sizeof(file
->digests
.sha2_256
);
929 return file
->digests
.sha2_256
;
931 case PAKFIRE_DIGEST_UNDEFINED
:
938 PAKFIRE_EXPORT
int pakfire_file_set_digest(struct pakfire_file
* file
,
939 const enum pakfire_digest_types type
, const unsigned char* digest
, const size_t length
) {
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
);
954 case PAKFIRE_DIGEST_SHA3_512
:
955 memcpy(file
->digests
.sha3_512
, digest
, sizeof(file
->digests
.sha3_512
));
958 case PAKFIRE_DIGEST_SHA3_256
:
959 memcpy(file
->digests
.sha3_256
, digest
, sizeof(file
->digests
.sha3_256
));
962 case PAKFIRE_DIGEST_BLAKE2B512
:
963 memcpy(file
->digests
.blake2b512
, digest
, sizeof(file
->digests
.blake2b512
));
966 case PAKFIRE_DIGEST_BLAKE2S256
:
967 memcpy(file
->digests
.blake2s256
, digest
, sizeof(file
->digests
.blake2s256
));
970 case PAKFIRE_DIGEST_SHA2_512
:
971 memcpy(file
->digests
.sha2_512
, digest
, sizeof(file
->digests
.sha2_512
));
974 case PAKFIRE_DIGEST_SHA2_256
:
975 memcpy(file
->digests
.sha2_256
, digest
, sizeof(file
->digests
.sha2_256
));
978 case PAKFIRE_DIGEST_UNDEFINED
:
986 static int pakfire_file_levels(struct pakfire_file
* file
) {
992 for (char* p
= file
->path
; *p
; p
++) {
1000 FILE* pakfire_file_open(struct pakfire_file
* file
) {
1001 FILE* f
= fopen(file
->abspath
, "r");
1003 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->abspath
);
1008 int pakfire_file_payload_matches(struct pakfire_file
* file
,
1009 const void* needle
, const size_t length
) {
1010 char buffer
[1024 * 1024];
1015 // Only run for regular files
1016 if (!S_ISREG(file
->st
.st_mode
))
1020 if (!file
->st
.st_size
)
1024 f
= pakfire_file_open(file
);
1031 size_t bytes_read
= fread(buffer
, 1, sizeof(buffer
), f
);
1033 // Raise any reading errors
1039 // Search for the needle
1040 p
= memmem(buffer
, bytes_read
, needle
, length
);
1057 static int __pakfire_file_compute_digests(struct pakfire_file
* file
,
1058 struct pakfire_digests
* digests
, const int types
) {
1062 // Skip this for anything that isn't a regular file
1063 if (!S_ISREG(file
->st
.st_mode
))
1067 pakfire_digests_reset(digests
, types
);
1070 f
= pakfire_file_open(file
);
1075 r
= pakfire_digests_compute_from_file(file
->pakfire
, digests
, types
, f
);
1086 int pakfire_file_compute_digests(struct pakfire_file
* file
, const int types
) {
1087 return __pakfire_file_compute_digests(file
, &file
->digests
, types
);
1090 int pakfire_file_remove(struct pakfire_file
* file
) {
1091 if (!*file
->abspath
) {
1096 DEBUG(file
->pakfire
, "Removing %s...\n", file
->path
);
1098 int r
= remove(file
->abspath
);
1101 // Ignore when we could not remove directories
1105 // Ignore if the file didn't exist
1113 ERROR(file
->pakfire
, "Could not remove %s (%s): %m\n", file
->path
, file
->abspath
);
1119 int 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
)) {
1126 return pakfire_path_exists(file
->abspath
);
1133 int pakfire_file_detect_mimetype(struct pakfire_file
* file
) {
1134 // Only process regular files
1135 if (!S_ISREG(file
->st
.st_mode
))
1138 // Skip if MIME type is already set
1139 if (*file
->mimetype
)
1142 // Fetch the magic cookie
1143 magic_t magic
= pakfire_get_magic(file
->pakfire
);
1148 const char* mimetype
= magic_file(magic
, file
->abspath
);
1150 ERROR(file
->pakfire
, "Could not classify %s: %s\n", file
->path
, magic_error(magic
));
1154 DEBUG(file
->pakfire
, "Classified %s as %s\n", file
->path
, mimetype
);
1157 return pakfire_file_set_mimetype(file
, mimetype
);
1160 PAKFIRE_EXPORT
const char* pakfire_file_get_mimetype(struct pakfire_file
* file
) {
1161 // Return nothing on an empty mimetype
1162 if (!*file
->mimetype
)
1165 return file
->mimetype
;
1168 PAKFIRE_EXPORT
int pakfire_file_set_mimetype(
1169 struct pakfire_file
* file
, const char* mimetype
) {
1171 return pakfire_string_set(file
->mimetype
, mimetype
);
1178 static 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));
1189 static int pakfire_file_classify_mode(struct pakfire_file
* file
) {
1190 // Check for regular files
1191 if (S_ISREG(file
->st
.st_mode
)) {
1192 file
->class |= PAKFIRE_FILE_REGULAR
;
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
;
1198 // Check for directories
1199 } else if (S_ISDIR(file
->st
.st_mode
))
1200 file
->class |= PAKFIRE_FILE_DIRECTORY
;
1202 // Check for symlinks
1203 else if (S_ISLNK(file
->st
.st_mode
))
1204 file
->class |= PAKFIRE_FILE_SYMLINK
;
1206 // Check for character devices
1207 else if (S_ISCHR(file
->st
.st_mode
))
1208 file
->class |= PAKFIRE_FILE_CHARACTER
;
1210 // Check for block devices
1211 else if (S_ISBLK(file
->st
.st_mode
))
1212 file
->class |= PAKFIRE_FILE_BLOCK
;
1214 // Check for FIFO pipes
1215 else if (S_ISFIFO(file
->st
.st_mode
))
1216 file
->class |= PAKFIRE_FILE_FIFO
;
1218 // Check for sockets
1219 else if (S_ISSOCK(file
->st
.st_mode
))
1220 file
->class |= PAKFIRE_FILE_SOCKET
;
1225 static const struct pattern
{
1226 const char* pattern
;
1229 { "*.a", PAKFIRE_FILE_STATIC_LIBRARY
},
1230 { "*.la", PAKFIRE_FILE_LIBTOOL_ARCHIVE
},
1231 { "*.pm", PAKFIRE_FILE_PERL
},
1232 { "*.pc", PAKFIRE_FILE_PKGCONFIG
},
1233 { "/usr/lib/firmware/*", PAKFIRE_FILE_FIRMWARE
},
1234 { "/usr/lib*/ld-*.so*", PAKFIRE_FILE_RUNTIME_LINKER
},
1238 static 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;
1249 static const struct mimetype
{
1250 const char* mimetype
;
1253 { "text/x-perl", PAKFIRE_FILE_PERL
},
1257 static int pakfire_file_classify_magic(struct pakfire_file
* file
) {
1260 // Detect the MIME type
1261 r
= pakfire_file_detect_mimetype(file
);
1265 // Fetch the MIME type
1266 const char* mimetype
= pakfire_file_get_mimetype(file
);
1270 // Match the MIME type with a flag
1271 for (const struct mimetype
* m
= mimetypes
; m
->mimetype
; m
++) {
1272 if (strcmp(m
->mimetype
, mimetype
) == 0) {
1273 file
->class |= m
->class;
1281 static int pakfire_file_classify_elf(struct pakfire_file
* file
) {
1286 // Don't run this if we already know that file is an ELF file
1287 if (file
->class & PAKFIRE_FILE_ELF
)
1291 r
= setup_libelf(file
->pakfire
);
1296 f
= fopen(file
->abspath
, "r");
1298 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->path
);
1302 // Try to open the ELF file
1303 elf
= elf_begin(fileno(f
), ELF_C_READ
, NULL
);
1305 // We fail silently here, because this file might be in a different format
1309 switch (elf_kind(elf
)) {
1310 // Mark this file as an ELF file
1312 file
->class |= PAKFIRE_FILE_ELF
;
1315 // Ignore everything else
1329 int pakfire_file_classify(struct pakfire_file
* file
) {
1333 // First, check the mode so that we won't run magic on directories, symlinks, ...
1334 r
= pakfire_file_classify_mode(file
);
1338 // Only run this for regular files
1339 if (file
->class & PAKFIRE_FILE_REGULAR
) {
1340 // Then check for patterns
1341 r
= pakfire_file_classify_pattern(file
);
1345 // After that, we will use libmagic...
1346 r
= pakfire_file_classify_magic(file
);
1350 // Check if the file is an ELF file
1351 r
= pakfire_file_classify_elf(file
);
1361 file
->class = PAKFIRE_FILE_UNKNOWN
;
1366 int pakfire_file_matches_class(struct pakfire_file
* file
, const int class) {
1367 return pakfire_file_classify(file
) & class;
1371 This function tries to remove the file after it has been packaged.
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
1376 int pakfire_file_cleanup(struct pakfire_file
* file
) {
1377 char path
[PATH_MAX
];
1379 // Try removing the file
1380 int r
= pakfire_file_remove(file
);
1384 // Create a working copy of abspath
1385 r
= pakfire_string_set(path
, file
->abspath
);
1389 // See how many levels this file has
1390 int levels
= pakfire_file_levels(file
);
1392 // Walk all the way up and remove all parent directories if possible
1396 // Break if path is suddenly empty
1400 DEBUG(file
->pakfire
, "Trying to remove parent directory %s\n", path
);
1404 // Break on any error
1412 static int pakfire_file_verify_mode(struct pakfire_file
* file
, const struct stat
* st
) {
1413 const mode_t type
= pakfire_file_get_type(file
);
1415 // Did the type change?
1416 if (type
!= (st
->st_mode
& S_IFMT
)) {
1417 file
->verify_status
|= PAKFIRE_FILE_TYPE_CHANGED
;
1419 DEBUG(file
->pakfire
, "%s: File Type changed\n", file
->path
);
1422 const mode_t perms
= pakfire_file_get_perms(file
);
1424 // Check permissions
1425 if (perms
!= (st
->st_mode
& 0777)) {
1426 file
->verify_status
|= PAKFIRE_FILE_PERMISSIONS_CHANGED
;
1428 DEBUG(file
->pakfire
, "%s: Permissions changed\n", file
->path
);
1432 // XXX This does not check what it is supposed to check
1434 // Check if device node changed
1435 if (S_ISCHR(st
->st_mode
) || S_ISBLK(st
->st_mode
)) {
1436 const dev_t dev
= pakfire_file_get_dev(file
);
1438 if (dev
!= st
->st_dev
) {
1439 file
->verify_status
|= PAKFIRE_FILE_DEV_CHANGED
;
1441 DEBUG(file
->pakfire
, "%s: Device Node changed\n", file
->path
);
1449 static int pakfire_file_verify_size(struct pakfire_file
* file
, const struct stat
* st
) {
1450 // Nothing to do if size matches
1451 if (file
->st
.st_size
== st
->st_size
)
1455 file
->verify_status
|= PAKFIRE_FILE_SIZE_CHANGED
;
1457 DEBUG(file
->pakfire
, "%s: Filesize differs (expected %zu, got %zu byte(s))\n",
1458 file
->path
, file
->st
.st_size
, st
->st_size
);
1463 static int pakfire_file_verify_ownership(struct pakfire_file
* file
, const struct stat
* st
) {
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
);
1469 const uid_t uid
= st
->st_uid
;
1470 const gid_t gid
= st
->st_gid
;
1473 // Fetch owner & group
1474 struct passwd
* owner
= pakfire_getpwnam(file
->pakfire
, file
->uname
);
1475 struct group
* group
= pakfire_getgrnam(file
->pakfire
, file
->gname
);
1477 // Check if owner matches
1478 if (!owner
|| owner
->pw_uid
!= uid
) {
1479 file
->verify_status
|= PAKFIRE_FILE_OWNER_CHANGED
;
1481 DEBUG(file
->pakfire
, "%s: Owner differs\n", file
->path
);
1484 // Check if group matches
1485 if (!group
|| group
->gr_gid
!= gid
) {
1486 file
->verify_status
|= PAKFIRE_FILE_GROUP_CHANGED
;
1488 DEBUG(file
->pakfire
, "%s: Group differs\n", file
->path
);
1494 static int pakfire_file_verify_timestamps(struct pakfire_file
* file
, const struct stat
* st
) {
1495 // Check creation time
1496 if (file
->st
.st_ctime
!= st
->st_ctime
) {
1497 file
->verify_status
|= PAKFIRE_FILE_CTIME_CHANGED
;
1499 DEBUG(file
->pakfire
, "%s: Creation time changed\n", file
->path
);
1502 // Check modification time
1503 if (file
->st
.st_mtime
!= st
->st_mtime
) {
1504 file
->verify_status
|= PAKFIRE_FILE_MTIME_CHANGED
;
1506 DEBUG(file
->pakfire
, "%s: Modification time changed\n", file
->path
);
1512 static int pakfire_file_verify_payload(struct pakfire_file
* file
, const struct stat
* st
) {
1515 struct pakfire_digests computed_digests
;
1516 int digest_types
= PAKFIRE_DIGEST_UNDEFINED
;
1518 // Nothing to do for anything that isn't a regular file
1519 if (!S_ISREG(st
->st_mode
))
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
;
1528 // Check if this file has any digests at all
1529 digest_types
= pakfire_digest_has_any(&file
->digests
);
1531 if (!digest_types
) {
1532 ERROR(file
->pakfire
, "%s: No digests available\n", file
->path
);
1537 r
= __pakfire_file_compute_digests(file
, &computed_digests
, digest_types
);
1542 r
= pakfire_digests_compare(file
->pakfire
, &file
->digests
, &computed_digests
, digest_types
);
1544 file
->verify_status
|= PAKFIRE_FILE_PAYLOAD_CHANGED
;
1546 DEBUG(file
->pakfire
, "%s: Digest(s) do not match\n", file
->path
);
1554 Verify the file - i.e. does the metadata match what is on disk?
1556 int pakfire_file_verify(struct pakfire_file
* file
, int* status
) {
1560 DEBUG(file
->pakfire
, "Verifying %s...\n", file
->path
);
1563 r
= lstat(file
->abspath
, &st
);
1565 // File does not exist
1566 if (errno
== ENOENT
) {
1567 file
->verify_status
|= PAKFIRE_FILE_NOENT
;
1571 // Raise any other errors from stat()
1576 r
= pakfire_file_verify_mode(file
, &st
);
1581 r
= pakfire_file_verify_size(file
, &st
);
1586 r
= pakfire_file_verify_ownership(file
, &st
);
1590 // Verify timestamps
1591 r
= pakfire_file_verify_timestamps(file
, &st
);
1596 r
= pakfire_file_verify_payload(file
, &st
);
1603 PAKFIRE_EXPORT
int pakfire_file_matches(struct pakfire_file
* file
, const char* pattern
) {
1606 // Don't match on no pattern
1610 // Check if the pattern matches
1611 r
= fnmatch(pattern
, file
->path
, 0);
1630 static int pakfire_file_open_elf(struct pakfire_file
* file
,
1631 int (*callback
)(struct pakfire_file
* file
, Elf
* elf
, void* data
), void* data
) {
1636 // Don't run this for non-ELF files
1637 if (!pakfire_file_matches_class(file
, PAKFIRE_FILE_ELF
)) {
1643 r
= setup_libelf(file
->pakfire
);
1648 f
= fopen(file
->abspath
, "r");
1650 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->abspath
);
1654 // Parse the ELF header
1655 elf
= elf_begin(fileno(f
), ELF_C_READ
, NULL
);
1657 ERROR(file
->pakfire
, "Could not open ELF file: %s\n", elf_errmsg(-1));
1662 // Check if this is an ELF file
1663 switch (elf_kind(elf
)) {
1668 ERROR(file
->pakfire
, "%s is not an ELF object\n", file
->path
);
1673 // Call the callback
1674 r
= callback(file
, elf
, data
);
1685 static 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
) {
1691 // Walk through all sections
1693 s
= elf_nextscn(elf
, s
);
1697 // Fetch the section header
1698 gelf_getshdr(s
, &shdr
);
1700 // Return any matching sections
1701 if (shdr
.sh_type
== type
) {
1704 // Send header if requested
1706 gelf_getshdr(s
, header
);
1708 // Send data if requested
1710 *data
= elf_getdata(s
, NULL
);
1720 static int __pakfire_file_get_elf_type(struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1721 int* type
= (int*)data
;
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));
1731 *type
= ehdr
.e_type
;
1736 static int pakfire_file_get_elf_type(struct pakfire_file
* file
) {
1740 r
= pakfire_file_open_elf(file
, __pakfire_file_get_elf_type
, &type
);
1747 static int pakfire_file_elf_dyn_walk(struct pakfire_file
* file
, Elf
* elf
,
1748 int (*callback
)(struct pakfire_file
* file
,
1749 Elf
* elf
, const GElf_Shdr
* shdr
, const GElf_Dyn
* dyn
, void* data
),
1751 Elf_Scn
* dynamic
= NULL
;
1753 Elf_Data
* elf_data
= NULL
;
1757 // Find the dynamic linking information
1758 r
= pakfire_file_get_elf_section(file
, elf
, SHT_DYNAMIC
, &dynamic
, &shdr
, &elf_data
);
1760 ERROR(file
->pakfire
, "%s does not have a dynamic section\n", file
->path
);
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
))
1770 // Call the callback
1771 r
= callback(file
, elf
, &shdr
, &dyn
, data
);
1779 static int __pakfire_file_check_debuginfo(struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1780 Elf_Scn
* symtab
= NULL
;
1783 // Fetch the symbol table
1784 r
= pakfire_file_get_elf_section(file
, elf
, SHT_SYMTAB
, &symtab
, NULL
, NULL
);
1788 DEBUG(file
->pakfire
, "%s has no debug sections\n", file
->path
);
1791 file
->issues
|= PAKFIRE_FILE_MISSING_DEBUGINFO
;
1797 static int pakfire_file_check_debuginfo(struct pakfire_file
* file
) {
1798 switch (pakfire_file_get_elf_type(file
)) {
1799 // Do not check Relocatable Objects
1803 // Check everything else
1808 return pakfire_file_open_elf(file
, __pakfire_file_check_debuginfo
, NULL
);
1811 static int __pakfire_file_check_ssp(
1812 struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1813 Elf_Scn
* symtab
= NULL
;
1815 Elf_Data
* elf_data
= NULL
;
1817 const char* name
= NULL
;
1820 // Fetch the symbol table
1821 r
= pakfire_file_get_elf_section(file
, elf
, SHT_SYMTAB
, &symtab
, &shdr
, &elf_data
);
1823 ERROR(file
->pakfire
, "%s has no symbol table\n", file
->path
);
1827 // Count any global functions
1830 // Walk through all symbols
1831 for (unsigned int i
= 0; i
< shdr
.sh_size
/ shdr
.sh_entsize
; i
++) {
1832 gelf_getsym(elf_data
, i
, &symbol
);
1834 // Fetch the symbol name
1835 name
= elf_strptr(elf
, shdr
.sh_link
, symbol
.st_name
);
1837 // Skip empty section names
1838 if (!name
|| !*name
)
1841 // Exit if there is a symbol called "__stack_chk_fail"
1842 if (pakfire_string_startswith(name
, "__stack_chk_fail"))
1845 // Count any global functions
1846 if ((ELF64_ST_BIND(symbol
.st_info
) == STB_GLOBAL
) &&
1847 (ELF64_ST_TYPE(symbol
.st_info
) == STT_FUNC
))
1851 // We do not perform the check for libraries that do not contain any functions.
1852 // Some packages use shared libraries to provide data.
1854 DEBUG(file
->pakfire
, "%s: File has no functions. Skipping SSP check.\n", file
->path
);
1858 // The file does not seem to have SSP enabled
1859 file
->issues
|= PAKFIRE_FILE_MISSING_SSP
;
1864 static int pakfire_file_check_ssp(struct pakfire_file
* file
) {
1865 // Do not perform this check for runtime linkers
1866 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_RUNTIME_LINKER
))
1869 // We cannot perform this check if we don't have debuginfo
1870 if (file
->issues
& PAKFIRE_FILE_MISSING_DEBUGINFO
)
1873 return pakfire_file_open_elf(file
, __pakfire_file_check_ssp
, NULL
);
1876 static int pakfire_file_check_pie(struct pakfire_file
* file
) {
1877 switch (pakfire_file_get_elf_type(file
)) {
1878 // Shared Object files are good
1882 // Everything else is bad
1884 file
->issues
|= PAKFIRE_FILE_MISSING_PIE
;
1891 static int __pakfire_file_check_execstack(
1892 struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1898 // Fetch the total numbers of program headers
1899 r
= elf_getphdrnum(elf
, &phnum
);
1901 ERROR(file
->pakfire
, "Could not fetch number of program headers: %s\n",
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));
1913 switch (phdr
.p_type
) {
1915 DEBUG(file
->pakfire
,
1916 "%s: GNU_STACK flags: %c%c%c\n",
1918 (phdr
.p_flags
& PF_R
) ? 'R' : '-',
1919 (phdr
.p_flags
& PF_W
) ? 'W' : '-',
1920 (phdr
.p_flags
& PF_X
) ? 'X' : '-'
1923 // The stack cannot be writable and executable
1924 if ((phdr
.p_flags
& PF_W
) && (phdr
.p_flags
& PF_X
))
1925 file
->issues
|= PAKFIRE_FILE_EXECSTACK
;
1938 static int pakfire_file_check_execstack(struct pakfire_file
* file
) {
1939 return pakfire_file_open_elf(file
, __pakfire_file_check_execstack
, NULL
);
1942 static int __pakfire_file_check_partially_relro(
1943 struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1949 // Fetch the total numbers of program headers
1950 r
= elf_getphdrnum(elf
, &phnum
);
1952 ERROR(file
->pakfire
, "Could not fetch number of program headers: %s\n",
1957 // Walk through all program headers
1958 for (unsigned int i
= 0; i
< phnum
; i
++) {
1959 if (!gelf_getphdr(elf
, i
, &phdr
)) {
1960 ERROR(file
->pakfire
, "Could not parse program header: %s\n", elf_errmsg(-1));
1964 switch (phdr
.p_type
) {
1973 // This file does not seem to have PT_GNU_RELRO set
1974 file
->issues
|= PAKFIRE_FILE_NO_RELRO
;
1979 static int pakfire_file_check_relro(struct pakfire_file
* file
) {
1980 return pakfire_file_open_elf(file
, __pakfire_file_check_relro
, NULL
);
1986 static int __pakfire_file_process_runpath(struct pakfire_file
* file
,
1987 Elf
* elf
, const GElf_Shdr
* shdr
, const GElf_Dyn
* dyn
, void* data
) {
1988 const char* value
= NULL
;
1989 const char* runpath
= NULL
;
1990 char buffer
[PATH_MAX
];
1994 switch (dyn
->d_tag
) {
1998 value
= elf_strptr(elf
, shdr
->sh_link
, dyn
->d_un
.d_val
);
2002 DEBUG(file
->pakfire
, "%s has a RUNPATH: %s\n", file
->path
, value
);
2004 // Copy the value into a buffer we can modify
2005 r
= pakfire_string_set(buffer
, value
);
2009 // Split the value by :
2010 runpath
= strtok_r(buffer
, ":", &p
);
2012 // Iterate over all elements
2014 DEBUG(file
->pakfire
, "Checking RUNPATH %s\n", runpath
);
2016 // We do not allow any relative RUNPATHs
2017 if (pakfire_path_match(runpath
, "**/../**")) {
2018 file
->issues
|= PAKFIRE_FILE_HAS_RUNPATH
;
2023 We allow some RUNPATHs where some software is loading some
2024 modules as shared objects from a private directory in /usr/lib64.
2026 if (!pakfire_path_match(runpath
, "/usr/lib64")
2027 && !pakfire_path_match(runpath
, "/usr/lib64/**")) {
2028 file
->issues
|= PAKFIRE_FILE_HAS_RUNPATH
;
2032 // Move on to the next RUNPATH
2033 runpath
= strtok_r(NULL
, ":", &p
);
2043 static int __pakfire_file_check_runpath(struct pakfire_file
* file
, Elf
* elf
, void* data
) {
2044 return pakfire_file_elf_dyn_walk(file
, elf
, __pakfire_file_process_runpath
, data
);
2047 static int pakfire_file_check_runpath(struct pakfire_file
* file
) {
2048 return pakfire_file_open_elf(file
, __pakfire_file_check_runpath
, NULL
);
2051 int pakfire_file_check(struct pakfire_file
* file
, int* issues
) {
2054 // Return previous result if this has been run before
2055 if (!file
->check_done
) {
2056 // Perform FHS check
2057 r
= pakfire_fhs_check_file(file
->pakfire
, file
);
2059 file
->issues
|= PAKFIRE_FILE_FHS_ERROR
;
2061 // Do not perform the following checks on firmware
2062 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_FIRMWARE
))
2065 // Run these checks only for ELF files
2066 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_ELF
)) {
2067 switch (pakfire_file_get_elf_type(file
)) {
2068 // Do not check Relocatable Objects
2072 // Check everything else
2077 // Check if the file has debug info
2078 r
= pakfire_file_check_debuginfo(file
);
2083 r
= pakfire_file_check_ssp(file
);
2088 r
= pakfire_file_check_pie(file
);
2092 // Check for executable stacks
2093 r
= pakfire_file_check_execstack(file
);
2098 r
= pakfire_file_check_relro(file
);
2102 // Check for RUNPATH
2103 r
= pakfire_file_check_runpath(file
);
2110 file
->check_done
= 1;
2113 // Return any issues
2115 *issues
= file
->issues
;