]> git.ipfire.org Git - pakfire.git/commitdiff
file: Read capabilities
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 18 Mar 2023 17:11:45 +0000 (17:11 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 18 Mar 2023 17:11:45 +0000 (17:11 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/file.c

index cc5054a1850d7dde50bd1881557d2a9872cb13d6..5b5e1b6b21e48a7a3003fc98788bc75e864ba781 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/limits.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/capability.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <time.h>
@@ -73,6 +74,9 @@ struct pakfire_file {
        // Stat
        struct stat st;
 
+       // Capabilities
+       cap_t caps;
+
        // Flags
        int flags;
 
@@ -96,11 +100,127 @@ struct pakfire_file {
        int issues;
        int check_done:1;
 
-       #warning TODO capabilities, data
-       // capabilities
+       #warning TODO data
        //int is_datafile;
 };
 
+/*
+       Capabilities
+*/
+static int pakfire_file_read_fcaps(struct pakfire_file* file,
+               const struct vfs_cap_data* cap_data, size_t length) {
+       int max = 0;
+       int r;
+
+       uint32_t magic_etc = le32toh(cap_data->magic_etc);
+
+       // Which version are we dealing with?
+       switch (magic_etc & VFS_CAP_REVISION_MASK) {
+               case VFS_CAP_REVISION_1:
+                       length -= XATTR_CAPS_SZ_1;
+                       max = VFS_CAP_U32_1;
+                       break;
+
+               case VFS_CAP_REVISION_2:
+                       length -= XATTR_CAPS_SZ_2;
+                       max = VFS_CAP_U32_2;
+                       break;
+
+               case VFS_CAP_REVISION_3:
+                       length -= XATTR_CAPS_SZ_3;
+                       max = VFS_CAP_U32_3;
+                       break;
+
+               // Unknown version
+               default:
+                       errno = EINVAL;
+                       return 1;
+       }
+
+       // Check if we have received the correct data
+       if (length) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       // Allocate capabilities
+       file->caps = cap_init();
+       if (!file->caps) {
+               ERROR(file->pakfire, "Could not allocate capabilities: %m\n");
+               r = 1;
+               goto ERROR;
+       }
+
+       int mask;
+       int index;
+
+       int cap_permitted;
+       int cap_inheritable;
+       int cap_effective = 0;
+
+       for (unsigned int cap = 0; cap_valid(cap); cap++) {
+               // Find the index where to find this cap
+               index = CAP_TO_INDEX(cap);
+               mask  = CAP_TO_MASK(cap);
+
+               // End if we have reached the end of the data
+               if (index > max)
+                       break;
+
+               // Check for permitted/inheritable flag set
+               cap_permitted   = le32toh(cap_data->data[index].permitted)   & mask;
+               cap_inheritable = le32toh(cap_data->data[index].inheritable) & mask;
+
+               // Check for effective
+               if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
+                       cap_effective = cap_permitted | cap_inheritable;
+
+               cap_value_t caps[] = { cap };
+
+               if (cap_permitted) {
+                       r = cap_set_flag(file->caps, CAP_PERMITTED, 1, caps, CAP_SET);
+                       if (r) {
+                               ERROR(file->pakfire, "Could not set capability %d: %m\n", cap);
+                               goto ERROR;
+                       }
+               }
+
+               if (cap_inheritable) {
+                       r = cap_set_flag(file->caps, CAP_INHERITABLE, 1, caps, CAP_SET);
+                       if (r) {
+                               ERROR(file->pakfire, "Could not set capability %d: %m\n", cap);
+                               goto ERROR;
+                       }
+               }
+
+               if (cap_effective) {
+                       r = cap_set_flag(file->caps, CAP_EFFECTIVE, 1, caps, CAP_SET);
+                       if (r) {
+                               ERROR(file->pakfire, "Could not set capability %d: %m\n", cap);
+                               goto ERROR;
+                       }
+               }
+       }
+
+#ifdef ENABLE_DEBUG
+       char* text = cap_to_text(file->caps, NULL);
+       if (text) {
+               DEBUG(file->pakfire, "%s: Capabilities %s\n", file->path, text);
+               cap_free(text);
+       }
+#endif
+
+       return 0;
+
+ERROR:
+       if (file->caps) {
+               cap_free(file->caps);
+               file->caps = NULL;
+       }
+
+       return r;
+}
+
 static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct archive_entry* entry) {
        char* buffer = NULL;
        const char* path = NULL;
@@ -224,6 +344,12 @@ static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct arc
                        if (r)
                                goto ERROR;
 
+               // Capabilities
+               } else if (strcmp(attr, "security.capability") == 0) {
+                       r = pakfire_file_read_fcaps(file, value, size);
+                       if (r)
+                               goto ERROR;
+
                } else {
                        DEBUG(file->pakfire, "Received an unknown extended attribute: %s\n", attr);
                }
@@ -424,6 +550,10 @@ ERROR:
 }
 
 static void pakfire_file_free(struct pakfire_file* file) {
+       // Free capabilities
+       if (file->caps)
+               cap_free(file->caps);
+
        pakfire_unref(file->pakfire);
        free(file);
 }