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>
28 #include <sys/capability.h>
30 #include <sys/types.h>
33 #include <archive_entry.h>
37 #include <pakfire/constants.h>
38 #include <pakfire/digest.h>
39 #include <pakfire/fhs.h>
40 #include <pakfire/file.h>
41 #include <pakfire/logging.h>
42 #include <pakfire/pakfire.h>
43 #include <pakfire/private.h>
44 #include <pakfire/string.h>
45 #include <pakfire/util.h>
47 enum pakfire_file_verification_status
{
48 PAKFIRE_FILE_NOENT
= (1 << 0),
49 PAKFIRE_FILE_TYPE_CHANGED
= (1 << 1),
50 PAKFIRE_FILE_PERMISSIONS_CHANGED
= (1 << 2),
51 PAKFIRE_FILE_DEV_CHANGED
= (1 << 3),
52 PAKFIRE_FILE_SIZE_CHANGED
= (1 << 4),
53 PAKFIRE_FILE_OWNER_CHANGED
= (1 << 5),
54 PAKFIRE_FILE_GROUP_CHANGED
= (1 << 6),
55 PAKFIRE_FILE_CTIME_CHANGED
= (1 << 7),
56 PAKFIRE_FILE_MTIME_CHANGED
= (1 << 8),
57 PAKFIRE_FILE_PAYLOAD_CHANGED
= (1 << 9),
61 struct pakfire
* pakfire
;
67 // The absolute path in the file system
68 char abspath
[PATH_MAX
];
71 char uname
[LOGIN_NAME_MAX
];
72 char gname
[LOGIN_NAME_MAX
];
84 char hardlink
[PATH_MAX
];
85 char symlink
[PATH_MAX
];
88 struct pakfire_digests digests
;
91 char mimetype
[NAME_MAX
];
96 // Verification Status
110 static int pakfire_file_read_fcaps(struct pakfire_file
* file
,
111 const struct vfs_cap_data
* cap_data
, size_t length
) {
115 uint32_t magic_etc
= le32toh(cap_data
->magic_etc
);
117 // Which version are we dealing with?
118 switch (magic_etc
& VFS_CAP_REVISION_MASK
) {
119 case VFS_CAP_REVISION_1
:
120 length
-= XATTR_CAPS_SZ_1
;
124 case VFS_CAP_REVISION_2
:
125 length
-= XATTR_CAPS_SZ_2
;
129 case VFS_CAP_REVISION_3
:
130 length
-= XATTR_CAPS_SZ_3
;
140 // Check if we have received the correct data
146 // Allocate capabilities
147 file
->caps
= cap_init();
149 ERROR(file
->pakfire
, "Could not allocate capabilities: %m\n");
159 int cap_effective
= 0;
161 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
162 // Find the index where to find this cap
163 index
= CAP_TO_INDEX(cap
);
164 mask
= CAP_TO_MASK(cap
);
166 // End if we have reached the end of the data
170 // Check for permitted/inheritable flag set
171 cap_permitted
= le32toh(cap_data
->data
[index
].permitted
) & mask
;
172 cap_inheritable
= le32toh(cap_data
->data
[index
].inheritable
) & mask
;
174 // Check for effective
175 if (magic_etc
& VFS_CAP_FLAGS_EFFECTIVE
)
176 cap_effective
= cap_permitted
| cap_inheritable
;
178 cap_value_t caps
[] = { cap
};
181 r
= cap_set_flag(file
->caps
, CAP_PERMITTED
, 1, caps
, CAP_SET
);
183 ERROR(file
->pakfire
, "Could not set capability %d: %m\n", cap
);
188 if (cap_inheritable
) {
189 r
= cap_set_flag(file
->caps
, CAP_INHERITABLE
, 1, caps
, CAP_SET
);
191 ERROR(file
->pakfire
, "Could not set capability %d: %m\n", cap
);
197 r
= cap_set_flag(file
->caps
, CAP_EFFECTIVE
, 1, caps
, CAP_SET
);
199 ERROR(file
->pakfire
, "Could not set capability %d: %m\n", cap
);
206 char* text
= cap_to_text(file
->caps
, NULL
);
208 DEBUG(file
->pakfire
, "%s: Capabilities %s\n", file
->path
, text
);
217 cap_free(file
->caps
);
224 int pakfire_file_write_fcaps(struct pakfire_file
* file
, struct vfs_cap_data
* cap_data
) {
225 cap_flag_value_t cap_permitted
;
226 cap_flag_value_t cap_inheritable
;
227 cap_flag_value_t cap_effective
;
230 // This should not be called when we have no caps
236 uint32_t magic
= VFS_CAP_REVISION_2
;
238 for (unsigned int cap
= 0; cap_valid(cap
); cap
++) {
239 // Find the index where to find this cap
240 int index
= CAP_TO_INDEX(cap
);
241 int mask
= CAP_TO_MASK(cap
);
243 // Fetch CAP_PERMITTED
244 r
= cap_get_flag(file
->caps
, cap
, CAP_PERMITTED
, &cap_permitted
);
246 ERROR(file
->pakfire
, "Could not fetch capability %d: %m\n", cap
);
250 // Fetch CAP_INHERITABLE
251 r
= cap_get_flag(file
->caps
, cap
, CAP_INHERITABLE
, &cap_inheritable
);
253 ERROR(file
->pakfire
, "Could not fetch capability %d: %m\n", cap
);
257 // Fetch CAP_EFFECTIVE
258 r
= cap_get_flag(file
->caps
, cap
, CAP_EFFECTIVE
, &cap_effective
);
260 ERROR(file
->pakfire
, "Could not fetch capability %d: %m\n", cap
);
264 // Store CAP_PERMITTED
266 cap_data
->data
[index
].permitted
|= htole32(mask
);
268 // Store CAP_INHERITED
270 cap_data
->data
[index
].inheritable
|= htole32(mask
);
272 // Set EFFECTIVE flag if CAP_EFFECTIVE is set
274 magic
|= VFS_CAP_FLAGS_EFFECTIVE
;
277 // Store the magic value
278 cap_data
->magic_etc
= htole32(magic
);
284 static int pakfire_file_from_archive_entry(struct pakfire_file
* file
, struct archive_entry
* entry
) {
286 const char* path
= NULL
;
287 const char* attr
= NULL
;
288 const void* value
= NULL
;
293 path
= archive_entry_sourcepath(entry
);
295 // Make path absolute
296 path
= pakfire_path_abspath(path
);
303 r
= pakfire_file_set_abspath(file
, path
);
305 ERROR(file
->pakfire
, "Could not set abspath: %m\n");
311 path
= archive_entry_pathname(entry
);
313 r
= pakfire_file_set_path(file
, path
);
315 ERROR(file
->pakfire
, "Could not set path: %m\n");
321 pakfire_file_set_hardlink(file
, archive_entry_hardlink(entry
));
322 pakfire_file_set_symlink(file
, archive_entry_symlink(entry
));
324 pakfire_file_set_nlink(file
, archive_entry_nlink(entry
));
325 pakfire_file_set_inode(file
, archive_entry_ino64(entry
));
326 pakfire_file_set_dev(file
, archive_entry_dev(entry
));
329 pakfire_file_set_size(file
, archive_entry_size(entry
));
332 pakfire_file_set_mode(file
, archive_entry_mode(entry
));
335 if (archive_entry_dev_is_set(entry
))
336 pakfire_file_set_dev(file
, archive_entry_dev(entry
));
339 pakfire_file_set_uname(file
, archive_entry_uname(entry
));
342 pakfire_file_set_gname(file
, archive_entry_gname(entry
));
345 pakfire_file_set_ctime(file
, archive_entry_ctime(entry
));
346 pakfire_file_set_mtime(file
, archive_entry_mtime(entry
));
348 // Reset iterating over extended attributes
349 archive_entry_xattr_reset(entry
);
351 // Read any extended attributes
352 while (archive_entry_xattr_next(entry
, &attr
, &value
, &size
) == ARCHIVE_OK
) {
354 if (strcmp(attr
, "PAKFIRE.config") == 0) {
355 r
= pakfire_file_set_flags(file
, PAKFIRE_FILE_CONFIG
);
360 } else if (strcmp(attr
, "PAKFIRE.mimetype") == 0) {
361 // Copy the value into a NULL-terminated buffer
362 r
= asprintf(&buffer
, "%.*s", (int)size
, (const char*)value
);
367 r
= pakfire_file_set_mimetype(file
, buffer
);
372 } else if (strcmp(attr
, "PAKFIRE.digests.sha3_512") == 0) {
373 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA3_512
, value
, size
);
378 } else if (strcmp(attr
, "PAKFIRE.digests.sha3_256") == 0) {
379 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA3_256
, value
, size
);
383 // Digest: BLAKE2b512
384 } else if (strcmp(attr
, "PAKFIRE.digests.blake2b512") == 0) {
385 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_BLAKE2B512
, value
, size
);
389 // Digest: BLAKE2s256
390 } else if (strcmp(attr
, "PAKFIRE.digests.blake2s256") == 0) {
391 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_BLAKE2S256
, value
, size
);
396 } else if (strcmp(attr
, "PAKFIRE.digests.sha2_512") == 0) {
397 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA2_512
, value
, size
);
402 } else if (strcmp(attr
, "PAKFIRE.digests.sha2_256") == 0) {
403 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA2_256
, value
, size
);
408 } else if (strcmp(attr
, "security.capability") == 0) {
409 r
= pakfire_file_read_fcaps(file
, value
, size
);
414 DEBUG(file
->pakfire
, "Received an unknown extended attribute: %s\n", attr
);
425 PAKFIRE_EXPORT
int pakfire_file_create(struct pakfire_file
** file
, struct pakfire
* pakfire
) {
426 struct pakfire_file
* f
= calloc(1, sizeof(*f
));
430 // Store reference to Pakfire
431 f
->pakfire
= pakfire_ref(pakfire
);
433 // Initialize reference counter
440 int pakfire_file_create_from_path(struct pakfire_file
** file
,
441 struct pakfire
* pakfire
, const char* path
) {
442 struct archive
* reader
= NULL
;
443 struct archive_entry
* entry
= NULL
;
447 reader
= pakfire_make_archive_disk_reader(pakfire
, 0);
451 // Allocate a new archive entry
452 entry
= archive_entry_new();
457 archive_entry_copy_sourcepath(entry
, path
);
459 // Read all file attributes from disk
460 r
= archive_read_disk_entry_from_file(reader
, entry
, -1, NULL
);
462 ERROR(pakfire
, "Could not read from %s: %m\n", path
);
467 r
= pakfire_file_create_from_archive_entry(file
, pakfire
, entry
);
473 ERROR(pakfire
, "Could not create file from path %s: %m\n", path
);
475 archive_entry_free(entry
);
477 archive_read_free(reader
);
482 int pakfire_file_create_from_archive_entry(struct pakfire_file
** file
, struct pakfire
* pakfire
,
483 struct archive_entry
* entry
) {
484 int r
= pakfire_file_create(file
, pakfire
);
488 // Copy archive entry
489 r
= pakfire_file_from_archive_entry(*file
, entry
);
496 pakfire_file_unref(*file
);
502 struct archive_entry
* pakfire_file_archive_entry(struct pakfire_file
* file
, int digest_types
) {
503 struct vfs_cap_data cap_data
= {};
504 const char* path
= NULL
;
507 struct archive_entry
* entry
= archive_entry_new();
509 ERROR(file
->pakfire
, "Could not allocate archive entry: %m\n");
514 archive_entry_copy_sourcepath(entry
, file
->abspath
);
517 path
= pakfire_file_get_path(file
);
518 if (path
&& *path
== '/') {
519 archive_entry_copy_pathname(entry
, path
+ 1);
524 archive_entry_set_hardlink(entry
, file
->hardlink
);
526 archive_entry_set_symlink(entry
, file
->symlink
);
528 archive_entry_set_nlink(entry
, pakfire_file_get_nlink(file
));
529 archive_entry_set_ino64(entry
, pakfire_file_get_inode(file
));
530 archive_entry_set_dev(entry
, pakfire_file_get_dev(file
));
533 archive_entry_set_size(entry
, pakfire_file_get_size(file
));
536 archive_entry_set_mode(entry
, pakfire_file_get_mode(file
));
539 archive_entry_set_uname(entry
, pakfire_file_get_uname(file
));
542 archive_entry_set_gname(entry
, pakfire_file_get_gname(file
));
545 archive_entry_set_ctime(entry
, pakfire_file_get_ctime(file
), 0);
546 archive_entry_set_mtime(entry
, pakfire_file_get_mtime(file
), 0);
549 if (pakfire_file_has_flag(file
, PAKFIRE_FILE_CONFIG
)) {
550 archive_entry_xattr_add_entry(entry
,
551 "PAKFIRE.config", "1", strlen("1"));
555 const char* mimetype
= pakfire_file_get_mimetype(file
);
557 archive_entry_xattr_add_entry(entry
,
558 "PAKFIRE.mimetype", mimetype
, strlen(mimetype
));
561 // Compute any required file digests
562 r
= pakfire_file_compute_digests(file
, digest_types
);
569 if ((digest_types
&& PAKFIRE_DIGEST_SHA3_512
)
570 && pakfire_digest_set(file
->digests
.sha3_512
))
571 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha3_512",
572 file
->digests
.sha3_512
, sizeof(file
->digests
.sha3_512
));
575 if ((digest_types
&& PAKFIRE_DIGEST_SHA3_256
) &&
576 pakfire_digest_set(file
->digests
.sha3_256
))
577 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha3_256",
578 file
->digests
.sha3_256
, sizeof(file
->digests
.sha3_256
));
581 if ((digest_types
&& PAKFIRE_DIGEST_BLAKE2B512
) &&
582 pakfire_digest_set(file
->digests
.blake2b512
))
583 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.blake2b512",
584 file
->digests
.blake2b512
, sizeof(file
->digests
.blake2b512
));
587 if ((digest_types
&& PAKFIRE_DIGEST_BLAKE2S256
) &&
588 pakfire_digest_set(file
->digests
.blake2s256
))
589 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.blake2s256",
590 file
->digests
.blake2s256
, sizeof(file
->digests
.blake2s256
));
593 if ((digest_types
&& PAKFIRE_DIGEST_SHA2_512
) &&
594 pakfire_digest_set(file
->digests
.sha2_512
))
595 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha2_512",
596 file
->digests
.sha2_512
, sizeof(file
->digests
.sha2_512
));
599 if ((digest_types
&& PAKFIRE_DIGEST_SHA2_512
) &&
600 pakfire_digest_set(file
->digests
.sha2_256
))
601 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha2_256",
602 file
->digests
.sha2_256
, sizeof(file
->digests
.sha2_256
));
606 r
= pakfire_file_write_fcaps(file
, &cap_data
);
608 ERROR(file
->pakfire
, "Could not export capabilities: %m\n");
612 // Store capabilities in archive entry
613 archive_entry_xattr_add_entry(entry
,
614 "security.capability", &cap_data
, sizeof(cap_data
));
621 archive_entry_free(entry
);
626 static void pakfire_file_free(struct pakfire_file
* file
) {
629 cap_free(file
->caps
);
631 pakfire_unref(file
->pakfire
);
635 PAKFIRE_EXPORT
struct pakfire_file
* pakfire_file_ref(struct pakfire_file
* file
) {
641 PAKFIRE_EXPORT
struct pakfire_file
* pakfire_file_unref(struct pakfire_file
* file
) {
642 if (--file
->nrefs
> 0)
645 pakfire_file_free(file
);
653 int pakfire_file_has_flag(struct pakfire_file
* file
, int flag
) {
654 return file
->flags
& flag
;
657 int pakfire_file_set_flags(struct pakfire_file
* file
, int flag
) {
663 #define pakfire_file_strmode(file, buffer) \
664 __pakfire_file_strmode(file, buffer, sizeof(buffer))
666 static int __pakfire_file_strmode(struct pakfire_file
* file
, char* s
, const size_t length
) {
669 static const mode_t permbits
[] = {
681 const mode_t mode
= pakfire_file_get_mode(file
);
682 const mode_t type
= pakfire_file_get_type(file
);
684 // Set some default string
685 r
= __pakfire_string_set(s
, length
, "?rwxrwxrwx ");
719 if (*file
->hardlink
) {
725 for (unsigned int i
= 0; i
< 9; i
++) {
726 if (mode
& permbits
[i
])
732 if (mode
& S_ISUID
) {
739 if (mode
& S_ISGID
) {
746 if (mode
& S_ISVTX
) {
761 char* pakfire_file_dump(struct pakfire_file
* file
, int flags
) {
769 if (flags
& PAKFIRE_FILE_DUMP_MODE
) {
770 r
= pakfire_file_strmode(file
, mode
);
774 r
= asprintf(&buffer
, "%s %s", buffer
, mode
);
780 if (flags
& PAKFIRE_FILE_DUMP_OWNERSHIP
) {
781 r
= asprintf(&buffer
, "%s %s/%s", buffer
, file
->uname
, file
->gname
);
787 if (flags
& PAKFIRE_FILE_DUMP_SIZE
) {
788 r
= asprintf(&buffer
, "%s %8zu", buffer
, file
->st
.st_size
);
794 if (flags
& PAKFIRE_FILE_DUMP_TIME
) {
795 r
= pakfire_strftime(time
, "%Y-%m-%d %H:%M", file
->st
.st_ctime
);
799 r
= asprintf(&buffer
, "%s %s", buffer
, time
);
805 r
= asprintf(&buffer
, "%s %s", buffer
, file
->path
);
809 // Append symlink target
810 if (flags
& PAKFIRE_FILE_DUMP_LINK_TARGETS
) {
811 switch (pakfire_file_get_type(file
)) {
813 r
= asprintf(&buffer
, "%s -> %s", buffer
, file
->symlink
);
823 if (flags
& PAKFIRE_FILE_DUMP_ISSUES
) {
824 if (file
->issues
& PAKFIRE_FILE_FHS_ERROR
) {
825 r
= asprintf(&buffer
, "%s [FHS-ERROR]", buffer
);
830 if (file
->issues
& PAKFIRE_FILE_MISSING_DEBUGINFO
) {
831 r
= asprintf(&buffer
, "%s [MISSING-DEBUGINFO]", buffer
);
836 // Stack-smashing Protection
837 if (file
->issues
& PAKFIRE_FILE_MISSING_SSP
) {
838 r
= asprintf(&buffer
, "%s [MISSING-SSP]", buffer
);
843 // Position-independent Executable
844 if (file
->issues
& PAKFIRE_FILE_MISSING_PIE
) {
845 r
= asprintf(&buffer
, "%s [MISSING-PIE]", buffer
);
851 if (file
->issues
& PAKFIRE_FILE_EXECSTACK
) {
852 r
= asprintf(&buffer
, "%s [EXECSTACK]", buffer
);
858 if (file
->issues
& PAKFIRE_FILE_NO_RELRO
) {
859 r
= asprintf(&buffer
, "%s [NO-RELRO]", buffer
);
865 if (file
->issues
& PAKFIRE_FILE_HAS_RUNPATH
) {
866 r
= asprintf(&buffer
, "%s [HAS-RUNPATH]", buffer
);
871 // Invalid capabilities
872 if (file
->issues
& PAKFIRE_FILE_INVALID_CAPS
) {
873 r
= asprintf(&buffer
, "%s [INVALID-CAPS]", buffer
);
888 PAKFIRE_EXPORT
int pakfire_file_cmp(struct pakfire_file
* file1
, struct pakfire_file
* file2
) {
889 const char* path1
= pakfire_file_get_path(file1
);
890 const char* path2
= pakfire_file_get_path(file2
);
892 return strcmp(path1
, path2
);
895 const char* pakfire_file_get_abspath(struct pakfire_file
* file
) {
896 return file
->abspath
;
899 int pakfire_file_set_abspath(struct pakfire_file
* file
, const char* path
) {
902 // Check if path is set and absolute
903 if (!path
|| *path
!= '/') {
909 r
= pakfire_string_set(file
->abspath
, path
);
913 // Store path if it isn't set, yet
915 r
= pakfire_file_set_path(file
, path
);
923 ERROR(file
->pakfire
, "Could not set abspath '%s': %m\n", path
);
927 PAKFIRE_EXPORT
const char* pakfire_file_get_path(struct pakfire_file
* file
) {
931 PAKFIRE_EXPORT
int pakfire_file_set_path(struct pakfire_file
* file
, const char* path
) {
934 // Check if path is set
940 // Strip any leading dots from paths
941 if (pakfire_string_startswith(path
, "./"))
945 // Just store the path if it is absolute
947 r
= pakfire_string_set(file
->path
, path
);
952 // Handle relative paths
954 r
= pakfire_string_format(file
->path
, "/%s", path
);
960 // Set abspath if it isn't set, yet
961 if (!*file
->abspath
) {
962 r
= pakfire_file_set_abspath(file
, file
->path
);
970 ERROR(file
->pakfire
, "Could not set path '%s': %m\n", path
);
974 PAKFIRE_EXPORT
const char* pakfire_file_get_hardlink(struct pakfire_file
* file
) {
975 if (!*file
->hardlink
)
978 return file
->hardlink
;
981 PAKFIRE_EXPORT
void pakfire_file_set_hardlink(struct pakfire_file
* file
, const char* link
) {
982 pakfire_string_set(file
->hardlink
, link
);
985 PAKFIRE_EXPORT
const char* pakfire_file_get_symlink(struct pakfire_file
* file
) {
989 return file
->symlink
;
992 PAKFIRE_EXPORT
void pakfire_file_set_symlink(struct pakfire_file
* file
, const char* link
) {
993 pakfire_string_set(file
->symlink
, link
);
996 PAKFIRE_EXPORT nlink_t
pakfire_file_get_nlink(struct pakfire_file
* file
) {
997 return file
->st
.st_nlink
;
1000 PAKFIRE_EXPORT
void pakfire_file_set_nlink(struct pakfire_file
* file
, const nlink_t nlink
) {
1001 file
->st
.st_nlink
= nlink
;
1004 PAKFIRE_EXPORT ino_t
pakfire_file_get_inode(struct pakfire_file
* file
) {
1005 return file
->st
.st_ino
;
1008 PAKFIRE_EXPORT
void pakfire_file_set_inode(struct pakfire_file
* file
, const ino_t ino
) {
1009 file
->st
.st_ino
= ino
;
1012 PAKFIRE_EXPORT dev_t
pakfire_file_get_dev(struct pakfire_file
* file
) {
1013 return file
->st
.st_dev
;
1016 PAKFIRE_EXPORT
void pakfire_file_set_dev(struct pakfire_file
* file
, const dev_t dev
) {
1017 file
->st
.st_dev
= dev
;
1020 PAKFIRE_EXPORT
int pakfire_file_get_type(struct pakfire_file
* file
) {
1021 return file
->st
.st_mode
& S_IFMT
;
1024 PAKFIRE_EXPORT off_t
pakfire_file_get_size(struct pakfire_file
* file
) {
1025 return file
->st
.st_size
;
1028 PAKFIRE_EXPORT
void pakfire_file_set_size(struct pakfire_file
* file
, off_t size
) {
1029 file
->st
.st_size
= size
;
1032 PAKFIRE_EXPORT
const char* pakfire_file_get_uname(struct pakfire_file
* file
) {
1036 PAKFIRE_EXPORT
int pakfire_file_set_uname(struct pakfire_file
* file
, const char* uname
) {
1037 return pakfire_string_set(file
->uname
, uname
);
1040 PAKFIRE_EXPORT
const char* pakfire_file_get_gname(struct pakfire_file
* file
) {
1044 PAKFIRE_EXPORT
int pakfire_file_set_gname(struct pakfire_file
* file
, const char* gname
) {
1045 return pakfire_string_set(file
->gname
, gname
);
1048 PAKFIRE_EXPORT mode_t
pakfire_file_get_mode(struct pakfire_file
* file
) {
1049 return file
->st
.st_mode
;
1052 PAKFIRE_EXPORT
void pakfire_file_set_mode(struct pakfire_file
* file
, mode_t mode
) {
1053 file
->st
.st_mode
= mode
;
1056 PAKFIRE_EXPORT mode_t
pakfire_file_get_perms(struct pakfire_file
* file
) {
1057 return file
->st
.st_mode
& ~S_IFMT
;
1060 PAKFIRE_EXPORT
void pakfire_file_set_perms(struct pakfire_file
* file
, const mode_t perms
) {
1061 // Clear any previous permissions
1062 file
->st
.st_mode
&= S_IFMT
;
1064 // Set new bits (with format cleared)
1065 file
->st
.st_mode
|= ~S_IFMT
& perms
;
1068 static int pakfire_file_is_executable(struct pakfire_file
* file
) {
1069 return file
->st
.st_mode
& (S_IXUSR
|S_IXGRP
|S_IXOTH
);
1072 PAKFIRE_EXPORT
time_t pakfire_file_get_ctime(struct pakfire_file
* file
) {
1073 return file
->st
.st_ctime
;
1076 PAKFIRE_EXPORT
void pakfire_file_set_ctime(struct pakfire_file
* file
, time_t time
) {
1077 file
->st
.st_ctime
= time
;
1080 PAKFIRE_EXPORT
time_t pakfire_file_get_mtime(struct pakfire_file
* file
) {
1081 return file
->st
.st_mtime
;
1084 PAKFIRE_EXPORT
void pakfire_file_set_mtime(struct pakfire_file
* file
, time_t time
) {
1085 file
->st
.st_mtime
= time
;
1088 PAKFIRE_EXPORT
const unsigned char* pakfire_file_get_digest(
1089 struct pakfire_file
* file
, const enum pakfire_digest_types type
, size_t* length
) {
1092 case PAKFIRE_DIGEST_SHA3_512
:
1093 if (!pakfire_digest_set(file
->digests
.sha3_512
))
1097 *length
= sizeof(file
->digests
.sha3_512
);
1099 return file
->digests
.sha3_512
;
1101 case PAKFIRE_DIGEST_SHA3_256
:
1102 if (!pakfire_digest_set(file
->digests
.sha3_256
))
1106 *length
= sizeof(file
->digests
.sha3_256
);
1108 return file
->digests
.sha3_256
;
1110 case PAKFIRE_DIGEST_BLAKE2B512
:
1111 if (!pakfire_digest_set(file
->digests
.blake2b512
))
1115 *length
= sizeof(file
->digests
.blake2b512
);
1117 return file
->digests
.blake2b512
;
1119 case PAKFIRE_DIGEST_BLAKE2S256
:
1120 if (!pakfire_digest_set(file
->digests
.blake2s256
))
1124 *length
= sizeof(file
->digests
.blake2s256
);
1126 return file
->digests
.blake2s256
;
1128 case PAKFIRE_DIGEST_SHA2_512
:
1129 if (!pakfire_digest_set(file
->digests
.sha2_512
))
1133 *length
= sizeof(file
->digests
.sha2_512
);
1135 return file
->digests
.sha2_512
;
1137 case PAKFIRE_DIGEST_SHA2_256
:
1138 if (!pakfire_digest_set(file
->digests
.sha2_256
))
1142 *length
= sizeof(file
->digests
.sha2_256
);
1144 return file
->digests
.sha2_256
;
1146 case PAKFIRE_DIGEST_UNDEFINED
:
1153 PAKFIRE_EXPORT
int pakfire_file_set_digest(struct pakfire_file
* file
,
1154 const enum pakfire_digest_types type
, const unsigned char* digest
, const size_t length
) {
1160 // Check buffer length
1161 if (pakfire_digest_length(type
) != length
) {
1162 ERROR(file
->pakfire
, "Digest has an incorrect length of %zu byte(s)\n", length
);
1169 case PAKFIRE_DIGEST_SHA3_512
:
1170 memcpy(file
->digests
.sha3_512
, digest
, sizeof(file
->digests
.sha3_512
));
1173 case PAKFIRE_DIGEST_SHA3_256
:
1174 memcpy(file
->digests
.sha3_256
, digest
, sizeof(file
->digests
.sha3_256
));
1177 case PAKFIRE_DIGEST_BLAKE2B512
:
1178 memcpy(file
->digests
.blake2b512
, digest
, sizeof(file
->digests
.blake2b512
));
1181 case PAKFIRE_DIGEST_BLAKE2S256
:
1182 memcpy(file
->digests
.blake2s256
, digest
, sizeof(file
->digests
.blake2s256
));
1185 case PAKFIRE_DIGEST_SHA2_512
:
1186 memcpy(file
->digests
.sha2_512
, digest
, sizeof(file
->digests
.sha2_512
));
1189 case PAKFIRE_DIGEST_SHA2_256
:
1190 memcpy(file
->digests
.sha2_256
, digest
, sizeof(file
->digests
.sha2_256
));
1193 case PAKFIRE_DIGEST_UNDEFINED
:
1201 PAKFIRE_EXPORT
int pakfire_file_has_caps(struct pakfire_file
* file
) {
1208 PAKFIRE_EXPORT
char* pakfire_file_get_caps(struct pakfire_file
* file
) {
1214 text
= cap_to_text(file
->caps
, &length
);
1216 ERROR(file
->pakfire
, "Could not export capabilities: %m\n");
1220 // libcap is being weird and uses its own allocator so we have to copy the string
1221 copy
= strndup(text
, length
);
1233 static int pakfire_file_levels(struct pakfire_file
* file
) {
1239 for (char* p
= file
->path
; *p
; p
++) {
1247 FILE* pakfire_file_open(struct pakfire_file
* file
) {
1248 FILE* f
= fopen(file
->abspath
, "r");
1250 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->abspath
);
1255 int pakfire_file_payload_matches(struct pakfire_file
* file
,
1256 const void* needle
, const size_t length
) {
1257 char buffer
[1024 * 1024];
1262 // Only run for regular files
1263 if (!S_ISREG(file
->st
.st_mode
))
1267 if (!file
->st
.st_size
)
1271 f
= pakfire_file_open(file
);
1278 size_t bytes_read
= fread(buffer
, 1, sizeof(buffer
), f
);
1280 // Raise any reading errors
1286 // Search for the needle
1287 p
= memmem(buffer
, bytes_read
, needle
, length
);
1304 static int __pakfire_file_compute_digests(struct pakfire_file
* file
,
1305 struct pakfire_digests
* digests
, const int types
) {
1309 // Skip this for anything that isn't a regular file
1310 if (!S_ISREG(file
->st
.st_mode
))
1314 pakfire_digests_reset(digests
, types
);
1317 f
= pakfire_file_open(file
);
1322 r
= pakfire_digests_compute_from_file(file
->pakfire
, digests
, types
, f
);
1333 int pakfire_file_compute_digests(struct pakfire_file
* file
, const int types
) {
1334 return __pakfire_file_compute_digests(file
, &file
->digests
, types
);
1337 static int pakfire_file_remove(struct pakfire_file
* file
) {
1340 if (!*file
->abspath
) {
1345 DEBUG(file
->pakfire
, "Removing %s...\n", file
->path
);
1347 switch (file
->st
.st_mode
& S_IFMT
) {
1348 // Call rmdir() for directories
1350 r
= rmdir(file
->abspath
);
1353 // Ignore when the directory is not empty
1358 // Ignore if the directory didn't exist
1363 // Ignore if the directory changed type
1368 // Log anything else
1370 ERROR(file
->pakfire
, "Could not remove directory %s: %m\n", file
->path
);
1376 // Call unlink() for everything else
1378 r
= unlink(file
->abspath
);
1381 // Ignore if the file didn't exist
1387 ERROR(file
->pakfire
, "Could not remove %s: %m\n", file
->path
);
1397 int pakfire_file_symlink_target_exists(struct pakfire_file
* file
) {
1398 // Fail if this got called for anything that isn't a symlink
1399 if (!S_ISLNK(file
->st
.st_mode
)) {
1404 return pakfire_path_exists(file
->abspath
);
1411 int pakfire_file_detect_mimetype(struct pakfire_file
* file
) {
1412 // Only process regular files
1413 if (!S_ISREG(file
->st
.st_mode
))
1416 // Skip if MIME type is already set
1417 if (*file
->mimetype
)
1420 // Fetch the magic cookie
1421 magic_t magic
= pakfire_get_magic(file
->pakfire
);
1426 const char* mimetype
= magic_file(magic
, file
->abspath
);
1428 ERROR(file
->pakfire
, "Could not classify %s: %s\n", file
->path
, magic_error(magic
));
1432 DEBUG(file
->pakfire
, "Classified %s as %s\n", file
->path
, mimetype
);
1435 return pakfire_file_set_mimetype(file
, mimetype
);
1438 PAKFIRE_EXPORT
const char* pakfire_file_get_mimetype(struct pakfire_file
* file
) {
1439 // Return nothing on an empty mimetype
1440 if (!*file
->mimetype
)
1443 return file
->mimetype
;
1446 PAKFIRE_EXPORT
int pakfire_file_set_mimetype(
1447 struct pakfire_file
* file
, const char* mimetype
) {
1449 return pakfire_string_set(file
->mimetype
, mimetype
);
1456 static int setup_libelf(struct pakfire
* pakfire
) {
1457 // Initialize libelf
1458 if (elf_version(EV_CURRENT
) == EV_NONE
) {
1459 ERROR(pakfire
, "Could not initialize libelf: %s\n", elf_errmsg(-1));
1467 static int pakfire_file_classify_mode(struct pakfire_file
* file
) {
1468 // Check for regular files
1469 if (S_ISREG(file
->st
.st_mode
)) {
1470 file
->class |= PAKFIRE_FILE_REGULAR
;
1472 // Does the file have executable permissions?
1473 if (file
->st
.st_mode
& (S_IXUSR
|S_IXGRP
|S_IXOTH
))
1474 file
->class |= PAKFIRE_FILE_EXECUTABLE
;
1476 // Check for directories
1477 } else if (S_ISDIR(file
->st
.st_mode
))
1478 file
->class |= PAKFIRE_FILE_DIRECTORY
;
1480 // Check for symlinks
1481 else if (S_ISLNK(file
->st
.st_mode
))
1482 file
->class |= PAKFIRE_FILE_SYMLINK
;
1484 // Check for character devices
1485 else if (S_ISCHR(file
->st
.st_mode
))
1486 file
->class |= PAKFIRE_FILE_CHARACTER
;
1488 // Check for block devices
1489 else if (S_ISBLK(file
->st
.st_mode
))
1490 file
->class |= PAKFIRE_FILE_BLOCK
;
1492 // Check for FIFO pipes
1493 else if (S_ISFIFO(file
->st
.st_mode
))
1494 file
->class |= PAKFIRE_FILE_FIFO
;
1496 // Check for sockets
1497 else if (S_ISSOCK(file
->st
.st_mode
))
1498 file
->class |= PAKFIRE_FILE_SOCKET
;
1503 static const struct pattern
{
1504 const char* pattern
;
1507 { "*.a", PAKFIRE_FILE_STATIC_LIBRARY
},
1508 { "*.la", PAKFIRE_FILE_LIBTOOL_ARCHIVE
},
1509 { "*.pm", PAKFIRE_FILE_PERL
},
1510 { "*.pc", PAKFIRE_FILE_PKGCONFIG
},
1511 { "/usr/lib/firmware/*", PAKFIRE_FILE_FIRMWARE
},
1512 { "/usr/lib/grub/*", PAKFIRE_FILE_FIRMWARE
},
1513 { "/usr/lib*/ld-*.so*", PAKFIRE_FILE_RUNTIME_LINKER
},
1517 static int pakfire_file_classify_pattern(struct pakfire_file
* file
) {
1518 for (const struct pattern
* p
= patterns
; p
->pattern
; p
++) {
1519 if (pakfire_file_matches(file
, p
->pattern
)) {
1520 file
->class |= p
->class;
1528 static const struct mimetype
{
1529 const char* mimetype
;
1532 { "text/x-perl", PAKFIRE_FILE_PERL
},
1536 static int pakfire_file_classify_magic(struct pakfire_file
* file
) {
1539 // Detect the MIME type
1540 r
= pakfire_file_detect_mimetype(file
);
1544 // Fetch the MIME type
1545 const char* mimetype
= pakfire_file_get_mimetype(file
);
1549 // Match the MIME type with a flag
1550 for (const struct mimetype
* m
= mimetypes
; m
->mimetype
; m
++) {
1551 if (strcmp(m
->mimetype
, mimetype
) == 0) {
1552 file
->class |= m
->class;
1560 static int pakfire_file_classify_elf(struct pakfire_file
* file
) {
1565 // Don't run this if we already know that file is an ELF file
1566 if (file
->class & PAKFIRE_FILE_ELF
)
1570 r
= setup_libelf(file
->pakfire
);
1575 f
= fopen(file
->abspath
, "r");
1577 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->path
);
1581 // Try to open the ELF file
1582 elf
= elf_begin(fileno(f
), ELF_C_READ
, NULL
);
1584 // We fail silently here, because this file might be in a different format
1588 switch (elf_kind(elf
)) {
1589 // Mark this file as an ELF file
1591 file
->class |= PAKFIRE_FILE_ELF
;
1594 // Ignore everything else
1608 int pakfire_file_classify(struct pakfire_file
* file
) {
1612 // First, check the mode so that we won't run magic on directories, symlinks, ...
1613 r
= pakfire_file_classify_mode(file
);
1617 // Only run this for regular files
1618 if (file
->class & PAKFIRE_FILE_REGULAR
) {
1619 // Then check for patterns
1620 r
= pakfire_file_classify_pattern(file
);
1624 // After that, we will use libmagic...
1625 r
= pakfire_file_classify_magic(file
);
1629 // Check if the file is an ELF file
1630 r
= pakfire_file_classify_elf(file
);
1640 file
->class = PAKFIRE_FILE_UNKNOWN
;
1645 int pakfire_file_matches_class(struct pakfire_file
* file
, const int class) {
1646 return pakfire_file_classify(file
) & class;
1650 This function tries to remove the file after it has been packaged.
1652 It will try to delete any parent directories as well and ignore if directories
1653 cannot be deleted because they might contain other files
1655 int pakfire_file_cleanup(struct pakfire_file
* file
, int flags
) {
1656 char path
[PATH_MAX
];
1658 // Try removing the file
1659 int r
= pakfire_file_remove(file
);
1663 // Try to tidy up afterwards
1664 if (flags
& PAKFIRE_FILE_CLEANUP_TIDY
) {
1665 // Create a working copy of abspath
1666 r
= pakfire_string_set(path
, file
->abspath
);
1670 // See how many levels this file has
1671 int levels
= pakfire_file_levels(file
);
1673 // Walk all the way up and remove all parent directories if possible
1677 // Break if path is suddenly empty
1681 DEBUG(file
->pakfire
, "Trying to remove parent directory %s\n", path
);
1685 // Break on any error
1694 static int pakfire_file_verify_mode(struct pakfire_file
* file
, const struct stat
* st
) {
1695 const mode_t type
= pakfire_file_get_type(file
);
1697 // Did the type change?
1698 if (type
!= (st
->st_mode
& S_IFMT
)) {
1699 file
->verify_status
|= PAKFIRE_FILE_TYPE_CHANGED
;
1701 DEBUG(file
->pakfire
, "%s: File Type changed\n", file
->path
);
1704 const mode_t perms
= pakfire_file_get_perms(file
);
1706 // Check permissions
1707 if (perms
!= (st
->st_mode
& 0777)) {
1708 file
->verify_status
|= PAKFIRE_FILE_PERMISSIONS_CHANGED
;
1710 DEBUG(file
->pakfire
, "%s: Permissions changed\n", file
->path
);
1714 // XXX This does not check what it is supposed to check
1716 // Check if device node changed
1717 if (S_ISCHR(st
->st_mode
) || S_ISBLK(st
->st_mode
)) {
1718 const dev_t dev
= pakfire_file_get_dev(file
);
1720 if (dev
!= st
->st_dev
) {
1721 file
->verify_status
|= PAKFIRE_FILE_DEV_CHANGED
;
1723 DEBUG(file
->pakfire
, "%s: Device Node changed\n", file
->path
);
1731 static int pakfire_file_verify_size(struct pakfire_file
* file
, const struct stat
* st
) {
1732 // Nothing to do if size matches
1733 if (file
->st
.st_size
== st
->st_size
)
1737 file
->verify_status
|= PAKFIRE_FILE_SIZE_CHANGED
;
1739 DEBUG(file
->pakfire
, "%s: Filesize differs (expected %zu, got %zu byte(s))\n",
1740 file
->path
, file
->st
.st_size
, st
->st_size
);
1745 static int pakfire_file_verify_ownership(struct pakfire_file
* file
, const struct stat
* st
) {
1748 const uid_t uid
= pakfire_unmap_id(file
->pakfire
, st
->st_uid
);
1749 const gid_t gid
= pakfire_unmap_id(file
->pakfire
, st
->st_gid
);
1751 const uid_t uid
= st
->st_uid
;
1752 const gid_t gid
= st
->st_gid
;
1755 // Fetch owner & group
1756 struct passwd
* owner
= pakfire_getpwnam(file
->pakfire
, file
->uname
);
1757 struct group
* group
= pakfire_getgrnam(file
->pakfire
, file
->gname
);
1759 // Check if owner matches
1760 if (!owner
|| owner
->pw_uid
!= uid
) {
1761 file
->verify_status
|= PAKFIRE_FILE_OWNER_CHANGED
;
1763 DEBUG(file
->pakfire
, "%s: Owner differs\n", file
->path
);
1766 // Check if group matches
1767 if (!group
|| group
->gr_gid
!= gid
) {
1768 file
->verify_status
|= PAKFIRE_FILE_GROUP_CHANGED
;
1770 DEBUG(file
->pakfire
, "%s: Group differs\n", file
->path
);
1776 static int pakfire_file_verify_timestamps(struct pakfire_file
* file
, const struct stat
* st
) {
1777 // Check creation time
1778 if (file
->st
.st_ctime
!= st
->st_ctime
) {
1779 file
->verify_status
|= PAKFIRE_FILE_CTIME_CHANGED
;
1781 DEBUG(file
->pakfire
, "%s: Creation time changed\n", file
->path
);
1784 // Check modification time
1785 if (file
->st
.st_mtime
!= st
->st_mtime
) {
1786 file
->verify_status
|= PAKFIRE_FILE_MTIME_CHANGED
;
1788 DEBUG(file
->pakfire
, "%s: Modification time changed\n", file
->path
);
1794 static int pakfire_file_verify_payload(struct pakfire_file
* file
, const struct stat
* st
) {
1797 struct pakfire_digests computed_digests
;
1798 int digest_types
= PAKFIRE_DIGEST_UNDEFINED
;
1800 // Nothing to do for anything that isn't a regular file
1801 if (!S_ISREG(st
->st_mode
))
1804 // Fast-path if size changed. The payload will have changed, too
1805 if (file
->verify_status
& PAKFIRE_FILE_SIZE_CHANGED
) {
1806 file
->verify_status
|= PAKFIRE_FILE_PAYLOAD_CHANGED
;
1810 // Check if this file has any digests at all
1811 digest_types
= pakfire_digest_has_any(&file
->digests
);
1813 if (!digest_types
) {
1814 ERROR(file
->pakfire
, "%s: No digests available\n", file
->path
);
1819 r
= __pakfire_file_compute_digests(file
, &computed_digests
, digest_types
);
1824 r
= pakfire_digests_compare(file
->pakfire
, &file
->digests
, &computed_digests
, digest_types
);
1826 file
->verify_status
|= PAKFIRE_FILE_PAYLOAD_CHANGED
;
1828 DEBUG(file
->pakfire
, "%s: Digest(s) do not match\n", file
->path
);
1836 Verify the file - i.e. does the metadata match what is on disk?
1838 int pakfire_file_verify(struct pakfire_file
* file
, int* status
) {
1842 DEBUG(file
->pakfire
, "Verifying %s...\n", file
->path
);
1845 r
= lstat(file
->abspath
, &st
);
1847 // File does not exist
1848 if (errno
== ENOENT
) {
1849 file
->verify_status
|= PAKFIRE_FILE_NOENT
;
1853 // Raise any other errors from stat()
1858 r
= pakfire_file_verify_mode(file
, &st
);
1863 r
= pakfire_file_verify_size(file
, &st
);
1868 r
= pakfire_file_verify_ownership(file
, &st
);
1872 // Verify timestamps
1873 r
= pakfire_file_verify_timestamps(file
, &st
);
1878 r
= pakfire_file_verify_payload(file
, &st
);
1885 PAKFIRE_EXPORT
int pakfire_file_matches(struct pakfire_file
* file
, const char* pattern
) {
1888 // Don't match on no pattern
1892 // Check if the pattern matches
1893 r
= fnmatch(pattern
, file
->path
, 0);
1912 static int pakfire_file_open_elf(struct pakfire_file
* file
,
1913 int (*callback
)(struct pakfire_file
* file
, Elf
* elf
, void* data
), void* data
) {
1918 // Don't run this for non-ELF files
1919 if (!pakfire_file_matches_class(file
, PAKFIRE_FILE_ELF
)) {
1925 r
= setup_libelf(file
->pakfire
);
1930 f
= fopen(file
->abspath
, "r");
1932 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->abspath
);
1936 // Parse the ELF header
1937 elf
= elf_begin(fileno(f
), ELF_C_READ
, NULL
);
1939 ERROR(file
->pakfire
, "Could not open ELF file: %s\n", elf_errmsg(-1));
1944 // Check if this is an ELF file
1945 switch (elf_kind(elf
)) {
1950 ERROR(file
->pakfire
, "%s is not an ELF object\n", file
->path
);
1955 // Call the callback
1956 r
= callback(file
, elf
, data
);
1967 static int pakfire_file_get_elf_section(struct pakfire_file
* file
,
1968 Elf
* elf
, const Elf64_Word type
, Elf_Scn
** section
, GElf_Shdr
* header
, Elf_Data
** data
) {
1973 // Walk through all sections
1975 s
= elf_nextscn(elf
, s
);
1979 // Fetch the section header
1980 gelf_getshdr(s
, &shdr
);
1982 // Return any matching sections
1983 if (shdr
.sh_type
== type
) {
1986 // Send header if requested
1988 gelf_getshdr(s
, header
);
1990 // Send data if requested
1992 *data
= elf_getdata(s
, NULL
);
2002 static int __pakfire_file_get_elf_type(struct pakfire_file
* file
, Elf
* elf
, void* data
) {
2003 int* type
= (int*)data
;
2006 // Fetch the ELF header
2007 if (!gelf_getehdr(elf
, &ehdr
)) {
2008 ERROR(file
->pakfire
, "Could not parse ELF header: %s\n", elf_errmsg(-1));
2013 *type
= ehdr
.e_type
;
2018 static int pakfire_file_get_elf_type(struct pakfire_file
* file
) {
2022 r
= pakfire_file_open_elf(file
, __pakfire_file_get_elf_type
, &type
);
2029 static int pakfire_file_elf_dyn_walk(struct pakfire_file
* file
, Elf
* elf
,
2030 int (*callback
)(struct pakfire_file
* file
,
2031 Elf
* elf
, const GElf_Shdr
* shdr
, const GElf_Dyn
* dyn
, void* data
),
2033 Elf_Scn
* dynamic
= NULL
;
2035 Elf_Data
* elf_data
= NULL
;
2039 // Find the dynamic linking information
2040 r
= pakfire_file_get_elf_section(file
, elf
, SHT_DYNAMIC
, &dynamic
, &shdr
, &elf_data
);
2042 ERROR(file
->pakfire
, "%s does not have a dynamic section\n", file
->path
);
2046 // Walk through all entries...
2047 for (unsigned int i
= 0; ; i
++) {
2048 // Fetch the next entry
2049 if (!gelf_getdyn(elf_data
, i
, &dyn
))
2052 // Call the callback
2053 r
= callback(file
, elf
, &shdr
, &dyn
, data
);
2061 static int __pakfire_file_check_debuginfo(struct pakfire_file
* file
, Elf
* elf
, void* data
) {
2062 Elf_Scn
* symtab
= NULL
;
2065 // Fetch the symbol table
2066 r
= pakfire_file_get_elf_section(file
, elf
, SHT_SYMTAB
, &symtab
, NULL
, NULL
);
2070 DEBUG(file
->pakfire
, "%s has no debug sections\n", file
->path
);
2073 file
->issues
|= PAKFIRE_FILE_MISSING_DEBUGINFO
;
2079 static int pakfire_file_check_debuginfo(struct pakfire_file
* file
) {
2080 switch (pakfire_file_get_elf_type(file
)) {
2081 // Do not check Relocatable Objects
2085 // Check everything else
2090 return pakfire_file_open_elf(file
, __pakfire_file_check_debuginfo
, NULL
);
2093 static int __pakfire_file_check_ssp(
2094 struct pakfire_file
* file
, Elf
* elf
, void* data
) {
2095 Elf_Scn
* symtab
= NULL
;
2097 Elf_Data
* elf_data
= NULL
;
2099 const char* name
= NULL
;
2102 // Fetch the symbol table
2103 r
= pakfire_file_get_elf_section(file
, elf
, SHT_SYMTAB
, &symtab
, &shdr
, &elf_data
);
2105 ERROR(file
->pakfire
, "%s has no symbol table\n", file
->path
);
2109 // Count any global functions
2112 // Walk through all symbols
2113 for (unsigned int i
= 0; i
< shdr
.sh_size
/ shdr
.sh_entsize
; i
++) {
2114 gelf_getsym(elf_data
, i
, &symbol
);
2116 // Fetch the symbol name
2117 name
= elf_strptr(elf
, shdr
.sh_link
, symbol
.st_name
);
2119 // Skip empty section names
2120 if (!name
|| !*name
)
2123 // Exit if there is a symbol called "__stack_chk_fail"
2124 if (pakfire_string_startswith(name
, "__stack_chk_fail"))
2127 // Count any global functions
2128 if ((ELF64_ST_BIND(symbol
.st_info
) == STB_GLOBAL
) &&
2129 (ELF64_ST_TYPE(symbol
.st_info
) == STT_FUNC
))
2133 // We do not perform the check for libraries that do not contain any functions.
2134 // Some packages use shared libraries to provide data.
2136 DEBUG(file
->pakfire
, "%s: File has no functions. Skipping SSP check.\n", file
->path
);
2140 // The file does not seem to have SSP enabled
2141 file
->issues
|= PAKFIRE_FILE_MISSING_SSP
;
2146 static int pakfire_file_check_ssp(struct pakfire_file
* file
) {
2147 // This check will be skipped for these files
2148 static const char* whitelist
[] = {
2149 "/usr/lib64/libgcc_s.so.*",
2150 "/usr/lib64/libmvec.so.*",
2154 // Do not perform this check for runtime linkers
2155 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_RUNTIME_LINKER
))
2158 // We cannot perform this check if we don't have debuginfo
2159 if (file
->issues
& PAKFIRE_FILE_MISSING_DEBUGINFO
)
2162 // Check if this file is whitelisted
2163 for (const char** path
= whitelist
; *path
; path
++) {
2164 if (pakfire_file_matches(file
, *path
)) {
2165 DEBUG(file
->pakfire
, "Skipping SSP check for whitelisted file %s\n",
2166 pakfire_file_get_path(file
));
2171 return pakfire_file_open_elf(file
, __pakfire_file_check_ssp
, NULL
);
2174 static int pakfire_file_check_pie(struct pakfire_file
* file
) {
2175 switch (pakfire_file_get_elf_type(file
)) {
2176 // Shared Object files are good
2180 // Everything else is bad
2182 file
->issues
|= PAKFIRE_FILE_MISSING_PIE
;
2189 static int __pakfire_file_check_execstack(
2190 struct pakfire_file
* file
, Elf
* elf
, void* data
) {
2196 // Fetch the total numbers of program headers
2197 r
= elf_getphdrnum(elf
, &phnum
);
2199 ERROR(file
->pakfire
, "Could not fetch number of program headers: %s\n",
2204 // Walk through all program headers
2205 for (unsigned int i
= 0; i
< phnum
; i
++) {
2206 if (!gelf_getphdr(elf
, i
, &phdr
)) {
2207 ERROR(file
->pakfire
, "Could not parse program header: %s\n", elf_errmsg(-1));
2211 switch (phdr
.p_type
) {
2213 DEBUG(file
->pakfire
,
2214 "%s: GNU_STACK flags: %c%c%c\n",
2216 (phdr
.p_flags
& PF_R
) ? 'R' : '-',
2217 (phdr
.p_flags
& PF_W
) ? 'W' : '-',
2218 (phdr
.p_flags
& PF_X
) ? 'X' : '-'
2221 // The stack cannot be writable and executable
2222 if ((phdr
.p_flags
& PF_W
) && (phdr
.p_flags
& PF_X
))
2223 file
->issues
|= PAKFIRE_FILE_EXECSTACK
;
2236 static int pakfire_file_check_execstack(struct pakfire_file
* file
) {
2237 return pakfire_file_open_elf(file
, __pakfire_file_check_execstack
, NULL
);
2240 static int __pakfire_file_process_bind_now(struct pakfire_file
* file
,
2241 Elf
* elf
, const GElf_Shdr
* shdr
, const GElf_Dyn
* dyn
, void* data
) {
2242 int* has_bind_now
= (int*)data
;
2244 switch (dyn
->d_tag
) {
2250 if (dyn
->d_un
.d_val
& DF_BIND_NOW
)
2255 if (dyn
->d_un
.d_val
& DF_1_NOW
)
2266 static int __pakfire_file_check_relro(
2267 struct pakfire_file
* file
, Elf
* elf
, void* data
) {
2268 int has_bind_now
= 0;
2272 // Check if we have BIND_NOW
2273 r
= pakfire_file_elf_dyn_walk(file
, elf
,
2274 __pakfire_file_process_bind_now
, &has_bind_now
);
2278 // We are not fully RELRO
2279 if (!has_bind_now
) {
2280 file
->issues
|= PAKFIRE_FILE_NO_RELRO
;
2285 // Walk through all program headers
2286 for (unsigned int i
= 0;; i
++) {
2287 if (!gelf_getphdr(elf
, i
, &phdr
))
2290 switch (phdr
.p_type
) {
2299 // This file does not seem to have PT_GNU_RELRO set
2300 file
->issues
|= PAKFIRE_FILE_NO_RELRO
;
2305 static int pakfire_file_check_relro(struct pakfire_file
* file
) {
2306 return pakfire_file_open_elf(file
, __pakfire_file_check_relro
, NULL
);
2312 static int __pakfire_file_process_runpath(struct pakfire_file
* file
,
2313 Elf
* elf
, const GElf_Shdr
* shdr
, const GElf_Dyn
* dyn
, void* data
) {
2314 const char* value
= NULL
;
2315 const char* runpath
= NULL
;
2316 char buffer
[PATH_MAX
];
2320 switch (dyn
->d_tag
) {
2324 value
= elf_strptr(elf
, shdr
->sh_link
, dyn
->d_un
.d_val
);
2328 DEBUG(file
->pakfire
, "%s has a RUNPATH: %s\n", file
->path
, value
);
2330 // Copy the value into a buffer we can modify
2331 r
= pakfire_string_set(buffer
, value
);
2335 // Split the value by :
2336 runpath
= strtok_r(buffer
, ":", &p
);
2338 // Iterate over all elements
2340 ERROR(file
->pakfire
, "Checking RUNPATH %s\n", runpath
);
2342 // We do not allow any relative RUNPATHs
2343 if (pakfire_path_match(runpath
, "**/../**"))
2344 goto RUNPATH_DENIED
;
2346 // We allow /usr/lib64 as libtool seems to link it in quite a lot
2347 if (pakfire_path_match("/usr/lib64", runpath
))
2348 goto RUNPATH_PERMITTED
;
2350 // We allow any subdirectories of /usr/lib64
2351 if (pakfire_path_match( "/usr/lib64/**", runpath
))
2352 goto RUNPATH_PERMITTED
;
2355 // If we make it here, this check has failed
2356 file
->issues
|= PAKFIRE_FILE_HAS_RUNPATH
;
2360 // Move on to the next RUNPATH
2361 runpath
= strtok_r(NULL
, ":", &p
);
2371 static int __pakfire_file_check_runpath(struct pakfire_file
* file
, Elf
* elf
, void* data
) {
2372 return pakfire_file_elf_dyn_walk(file
, elf
, __pakfire_file_process_runpath
, data
);
2375 static int pakfire_file_check_runpath(struct pakfire_file
* file
) {
2376 return pakfire_file_open_elf(file
, __pakfire_file_check_runpath
, NULL
);
2379 static int pakfire_file_check_capabilities(struct pakfire_file
* file
) {
2380 // Files cannot have capabilities but not be executable
2381 if (!pakfire_file_is_executable(file
) && pakfire_file_has_caps(file
))
2382 file
->issues
|= PAKFIRE_FILE_INVALID_CAPS
;
2388 int pakfire_file_check(struct pakfire_file
* file
, int* issues
) {
2391 // Return previous result if this has been run before
2392 if (!file
->check_done
) {
2393 // Perform FHS check
2394 r
= pakfire_fhs_check_file(file
->pakfire
, file
);
2396 file
->issues
|= PAKFIRE_FILE_FHS_ERROR
;
2398 // Perform capability check
2399 r
= pakfire_file_check_capabilities(file
);
2403 // Do not perform the following checks on firmware
2404 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_FIRMWARE
))
2407 // Run these checks only for ELF files
2408 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_ELF
)) {
2409 switch (pakfire_file_get_elf_type(file
)) {
2410 // Do not check Relocatable Objects
2414 // Check everything else
2419 // Check if the file has debug info
2420 r
= pakfire_file_check_debuginfo(file
);
2425 r
= pakfire_file_check_ssp(file
);
2430 r
= pakfire_file_check_pie(file
);
2434 // Check for executable stacks
2435 r
= pakfire_file_check_execstack(file
);
2440 r
= pakfire_file_check_relro(file
);
2444 // Check for RUNPATH
2445 r
= pakfire_file_check_runpath(file
);
2452 file
->check_done
= 1;
2455 // Return any issues
2457 *issues
= file
->issues
;