]> git.ipfire.org Git - pakfire.git/commitdiff
file: Write capabilities
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 19 Mar 2023 18:38:46 +0000 (18:38 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 19 Mar 2023 18:38:46 +0000 (18:38 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/compress.c
src/libpakfire/file.c
src/libpakfire/include/pakfire/file.h
src/libpakfire/libpakfire.sym

index 10120587c058057c5e43648bf49a8fa4d969013f..c25613837d45311d275b3f24d07130ae8c561cc9 100644 (file)
@@ -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) {
index 5b5e1b6b21e48a7a3003fc98788bc75e864ba781..756b9f913942f40283b15245152aff15b0236b96 100644 (file)
@@ -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;
index 431702ffe8b3d017f1a85e6d852b44ed925902ed..390c38194d50c6a04c1dd4839fea3cc113d2b01f 100644 (file)
@@ -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 <archive_entry.h>
 
+#include <sys/capability.h>
+
 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,
index 762d654a0f70e4d22dd98dae0ce656ca242e0870..091c4ee1cc0d29822200cdbe15aa3aa114a72ebd 100644 (file)
@@ -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;