From 729568d0b6eb669f68290e676970201a7b8d23b8 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sun, 19 Mar 2023 18:38:46 +0000 Subject: [PATCH] file: Write capabilities Signed-off-by: Michael Tremer --- src/libpakfire/compress.c | 12 +++ src/libpakfire/file.c | 106 ++++++++++++++++++++++++++ src/libpakfire/include/pakfire/file.h | 8 ++ src/libpakfire/libpakfire.sym | 2 + 4 files changed, 128 insertions(+) diff --git a/src/libpakfire/compress.c b/src/libpakfire/compress.c index 10120587c..c25613837 100644 --- a/src/libpakfire/compress.c +++ b/src/libpakfire/compress.c @@ -682,6 +682,7 @@ static void pakfire_extract_progress(void* p) { static int __pakfire_extract(struct pakfire* pakfire, struct archive* a, struct archive_entry* entry, void* p) { struct pakfire_file* file = NULL; + struct vfs_cap_data cap_data = {}; char buffer[PATH_MAX]; int r; @@ -760,6 +761,17 @@ static int __pakfire_extract(struct pakfire* pakfire, struct archive* a, // Remove any extended attributes which we never write to disk archive_entry_xattr_clear(entry); + // Set capabilities + if (pakfire_file_has_caps(file)) { + r = pakfire_file_write_fcaps(file, &cap_data); + if (r) + goto ERROR; + + // Store capabilities in archive entry + archive_entry_xattr_add_entry(entry, "security.capability", + &cap_data, sizeof(cap_data)); + } + // Write payload r = archive_read_extract2(data->archive, entry, data->writer); switch (r) { diff --git a/src/libpakfire/file.c b/src/libpakfire/file.c index 5b5e1b6b2..756b9f913 100644 --- a/src/libpakfire/file.c +++ b/src/libpakfire/file.c @@ -221,6 +221,66 @@ ERROR: return r; } +int pakfire_file_write_fcaps(struct pakfire_file* file, struct vfs_cap_data* cap_data) { + cap_flag_value_t cap_permitted; + cap_flag_value_t cap_inheritable; + cap_flag_value_t cap_effective; + int r; + + // This should not be called when we have no caps + if (!file->caps) { + errno = EINVAL; + return 1; + } + + uint32_t magic = VFS_CAP_REVISION_2; + + for (unsigned int cap = 0; cap_valid(cap); cap++) { + // Find the index where to find this cap + int index = CAP_TO_INDEX(cap); + int mask = CAP_TO_MASK(cap); + + // Fetch CAP_PERMITTED + r = cap_get_flag(file->caps, cap, CAP_PERMITTED, &cap_permitted); + if (r) { + ERROR(file->pakfire, "Could not fetch capability %d: %m\n", cap); + goto ERROR; + } + + // Fetch CAP_INHERITABLE + r = cap_get_flag(file->caps, cap, CAP_INHERITABLE, &cap_inheritable); + if (r) { + ERROR(file->pakfire, "Could not fetch capability %d: %m\n", cap); + goto ERROR; + } + + // Fetch CAP_EFFECTIVE + r = cap_get_flag(file->caps, cap, CAP_EFFECTIVE, &cap_effective); + if (r) { + ERROR(file->pakfire, "Could not fetch capability %d: %m\n", cap); + goto ERROR; + } + + // Store CAP_PERMITTED + if (cap_permitted) + cap_data->data[index].permitted |= htole32(mask); + + // Store CAP_INHERITED + if (cap_inheritable) + cap_data->data[index].inheritable |= htole32(mask); + + // Set EFFECTIVE flag if CAP_EFFECTIVE is set + if (cap_effective) + magic |= VFS_CAP_FLAGS_EFFECTIVE; + } + + // Store the magic value + cap_data->magic_etc = htole32(magic); + +ERROR: + return r; +} + static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct archive_entry* entry) { char* buffer = NULL; const char* path = NULL; @@ -440,6 +500,7 @@ ERROR: } struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int digest_types) { + struct vfs_cap_data cap_data = {}; const char* path = NULL; int r; @@ -540,6 +601,19 @@ struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_256", file->digests.sha2_256, sizeof(file->digests.sha2_256)); + // Capabilities + if (file->caps) { + r = pakfire_file_write_fcaps(file, &cap_data); + if (r) { + ERROR(file->pakfire, "Could not export capabilities: %m\n"); + goto ERROR; + } + + // Store capabilities in archive entry + archive_entry_xattr_add_entry(entry, + "security.capability", &cap_data, sizeof(cap_data)); + } + return entry; ERROR: @@ -1113,6 +1187,38 @@ PAKFIRE_EXPORT int pakfire_file_set_digest(struct pakfire_file* file, return 0; } +PAKFIRE_EXPORT int pakfire_file_has_caps(struct pakfire_file* file) { + if (file->caps) + return 1; + + return 0; +} + +PAKFIRE_EXPORT char* pakfire_file_get_caps(struct pakfire_file* file) { + char* copy = NULL; + char* text = NULL; + ssize_t length = 0; + + if (file->caps) { + text = cap_to_text(file->caps, &length); + if (!text) { + ERROR(file->pakfire, "Could not export capabilities: %m\n"); + goto ERROR; + } + + // libcap is being weird and uses its own allocator so we have to copy the string + copy = strndup(text, length); + if (!copy) + goto ERROR; + } + +ERROR: + if (text) + cap_free(text); + + return copy; +} + static int pakfire_file_levels(struct pakfire_file* file) { if (!*file->path) return 0; diff --git a/src/libpakfire/include/pakfire/file.h b/src/libpakfire/include/pakfire/file.h index 431702ffe..390c38194 100644 --- a/src/libpakfire/include/pakfire/file.h +++ b/src/libpakfire/include/pakfire/file.h @@ -88,6 +88,10 @@ const unsigned char* pakfire_file_get_digest(struct pakfire_file* file, int pakfire_file_set_digest(struct pakfire_file* file, const enum pakfire_digest_types type, const unsigned char* digest, const size_t length); +// Capabilities +int pakfire_file_has_caps(struct pakfire_file* file); +char* pakfire_file_get_caps(struct pakfire_file* file); + // MIME Type const char* pakfire_file_get_mimetype(struct pakfire_file* file); int pakfire_file_set_mimetype(struct pakfire_file* file, const char* mimetype); @@ -100,6 +104,8 @@ int pakfire_file_matches(struct pakfire_file* file, const char* pattern); #include +#include + enum pakfire_file_classes { PAKFIRE_FILE_UNKNOWN = 0, @@ -125,6 +131,8 @@ enum pakfire_file_classes { PAKFIRE_FILE_RUNTIME_LINKER = (1 << 14), }; +int pakfire_file_write_fcaps(struct pakfire_file* file, struct vfs_cap_data* cap_data); + int pakfire_file_create_from_path(struct pakfire_file** file, struct pakfire* pakfire, const char* path); int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire, diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index 762d654a0..091c4ee1c 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -82,6 +82,7 @@ global: # file pakfire_file_cmp; pakfire_file_create; + pakfire_file_get_caps; pakfire_file_get_ctime; pakfire_file_get_dev; pakfire_file_get_digest; @@ -97,6 +98,7 @@ global: pakfire_file_get_time; pakfire_file_get_type; pakfire_file_get_uname; + pakfire_file_has_caps; pakfire_file_matches; pakfire_file_set_ctime; pakfire_file_set_dev; -- 2.39.5