]> git.ipfire.org Git - pakfire.git/commitdiff
jail: Don't drop any capabilities
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 21 Jun 2023 15:25:19 +0000 (15:25 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 21 Jun 2023 15:25:19 +0000 (15:25 +0000)
This is not what we finally need, but we will try to give the jail as
many capabilities in its own namespace as possible.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/jail.c

index c3a864f19b48f7dd27583f73b4b2655132dcc217..a7f22b5fb4d2128c4a06d6bca0911ce53403e955 100644 (file)
@@ -932,111 +932,144 @@ int pakfire_jail_capture_stdout(struct pakfire* pakfire, void* data,
 
 // Capabilities
 
-static int pakfire_jail_drop_capabilities(struct pakfire_jail* jail) {
-       const int capabilities[] = {
-               // Deny access to the kernel's audit system
-               CAP_AUDIT_CONTROL,
-               CAP_AUDIT_READ,
-               CAP_AUDIT_WRITE,
-
-               // Deny suspending block devices
-               CAP_BLOCK_SUSPEND,
-
-               // Deny any stuff with BPF
-               CAP_BPF,
-
-               // Deny checkpoint restore
-               CAP_CHECKPOINT_RESTORE,
+// Logs all capabilities of the current process
+static int pakfire_jail_show_capabilities(struct pakfire_jail* jail) {
+       cap_t caps = NULL;
+       char* name = NULL;
+       cap_flag_value_t value_e;
+       cap_flag_value_t value_i;
+       cap_flag_value_t value_p;
+       int r;
 
-               // Deny opening files by inode number (open_by_handle_at)
-               CAP_DAC_READ_SEARCH,
+       // Fetch PID
+       pid_t pid = getpid();
 
-               // Deny setting SUID bits
-               CAP_FSETID,
+       // Fetch all capabilities
+       caps = cap_get_proc();
+       if (!caps) {
+               ERROR(jail->pakfire, "Could not fetch capabilities: %m\n");
+               r = 1;
+               goto ERROR;
+       }
 
-               // Deny locking more memory
-               CAP_IPC_LOCK,
+       DEBUG(jail->pakfire, "Capabilities of PID %d:\n", pid);
 
-               // Deny modifying any Apparmor/SELinux/SMACK configuration
-               CAP_MAC_ADMIN,
-               CAP_MAC_OVERRIDE,
+       // Iterate over all capabilities
+       for (unsigned int cap = 0; cap_valid(cap); cap++) {
+               name = cap_to_name(cap);
 
-               // Deny creating any special devices
-               CAP_MKNOD,
+               // Fetch effective value
+               r = cap_get_flag(caps, cap, CAP_EFFECTIVE, &value_e);
+               if (r)
+                       goto ERROR;
 
-               // Deny reading from syslog
-               CAP_SYSLOG,
+               // Fetch inheritable value
+               r = cap_get_flag(caps, cap, CAP_INHERITABLE, &value_i);
+               if (r)
+                       goto ERROR;
 
-               // Deny any admin actions (mount, sethostname, ...)
-               CAP_SYS_ADMIN,
+               // Fetch permitted value
+               r = cap_get_flag(caps, cap, CAP_PERMITTED, &value_p);
+               if (r)
+                       goto ERROR;
 
-               // Deny rebooting the system
-               CAP_SYS_BOOT,
+               DEBUG(jail->pakfire,
+                       "  %-24s : %c%c%c\n",
+                       name,
+                       (value_e == CAP_SET) ? 'e' : '-',
+                       (value_i == CAP_SET) ? 'i' : '-',
+                       (value_p == CAP_SET) ? 'p' : '-'
+               );
 
-               // Deny loading kernel modules
-               CAP_SYS_MODULE,
+               // Free name
+               cap_free(name);
+               name = NULL;
+       }
 
-               // Deny setting nice level
-               CAP_SYS_NICE,
+       // Success
+       r = 0;
 
-               // Deny access to /proc/kcore, /dev/mem, /dev/kmem
-               CAP_SYS_RAWIO,
+ERROR:
+       if (name)
+               cap_free(name);
+       if (caps)
+               cap_free(caps);
 
-               // Deny circumventing any resource limits
-               CAP_SYS_RESOURCE,
+       return r;
+}
 
-               // Deny setting the system time
-               CAP_SYS_TIME,
+static int pakfire_jail_set_capabilities(struct pakfire_jail* jail) {
+       cap_t caps = NULL;
+       char* name = NULL;
+       int r;
 
-               // Deny playing with suspend
-               CAP_WAKE_ALARM,
+       // Fetch capabilities
+       caps = cap_get_proc();
+       if (!caps) {
+               ERROR(jail->pakfire, "Could not read capabilities: %m\n");
+               r = 1;
+               goto ERROR;
+       }
 
-               0,
-       };
+       // Walk through all capabilities
+       for (cap_value_t cap = 0; cap_valid(cap); cap++) {
+               cap_value_t _caps[] = { cap };
 
-       DEBUG(jail->pakfire, "Dropping capabilities...\n");
+               // Fetch the name of the capability
+               name = cap_to_name(cap);
 
-       size_t num_caps = 0;
-       int r;
+               r = cap_set_flag(caps, CAP_EFFECTIVE, 1, _caps, CAP_SET);
+               if (r) {
+                       ERROR(jail->pakfire, "Could not set %s: %m\n", name);
+                       goto ERROR;
+               }
 
-       // Drop any capabilities
-       for (const int* cap = capabilities; *cap; cap++) {
-               r = prctl(PR_CAPBSET_DROP, *cap, 0, 0, 0);
+               r = cap_set_flag(caps, CAP_INHERITABLE, 1, _caps, CAP_SET);
                if (r) {
-                       ERROR(jail->pakfire, "Could not drop capability %d: %m\n", *cap);
-                       return r;
+                       ERROR(jail->pakfire, "Could not set %s: %m\n", name);
+                       goto ERROR;
                }
 
-               num_caps++;
-       }
+               r = cap_set_flag(caps, CAP_PERMITTED, 1, _caps, CAP_SET);
+               if (r) {
+                       ERROR(jail->pakfire, "Could not set %s: %m\n", name);
+                       goto ERROR;
+               }
 
-       // Fetch any capabilities
-       cap_t caps = cap_get_proc();
-       if (!caps) {
-               ERROR(jail->pakfire, "Could not read capabilities: %m\n");
-               return 1;
+               // Free name
+               cap_free(name);
+               name = NULL;
        }
 
-       /*
-               Set inheritable capabilities
-
-               This ensures that no processes will be able to gain any of the listed
-               capabilities again.
-       */
-       r = cap_set_flag(caps, CAP_INHERITABLE, num_caps, capabilities, CAP_CLEAR);
+       // Restore all capabilities
+       r = cap_set_proc(caps);
        if (r) {
-               ERROR(jail->pakfire, "cap_set_flag() failed: %m\n");
+               ERROR(jail->pakfire, "Restoring capabilities failed: %m\n");
                goto ERROR;
        }
 
-       // Restore capabilities
-       r = cap_set_proc(caps);
-       if (r) {
-               ERROR(jail->pakfire, "Could not restore capabilities: %m\n");
-               goto ERROR;
+       // Add all capabilities to the ambient set
+       for (unsigned int cap = 0; cap_valid(cap); cap++) {
+               name = cap_to_name(cap);
+
+               // Raise the capability
+               r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0);
+               if (r) {
+                       ERROR(jail->pakfire, "Could not set ambient capability %s: %m\n", name);
+                       goto ERROR;
+               }
+
+               // Free name
+               cap_free(name);
+               name = NULL;
        }
 
+       // Success
+       r = 0;
+
 ERROR:
+       if (name)
+               cap_free(name);
        if (caps)
                cap_free(caps);
 
@@ -1601,8 +1634,20 @@ static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exe
        if (r)
                return r;
 
-       // Drop capabilities
-       r = pakfire_jail_drop_capabilities(jail);
+       // Don't drop any capabilities on execve()
+       r = prctl(PR_SET_KEEPCAPS, 1);
+       if (r) {
+               ERROR(jail->pakfire, "Could not set PR_SET_KEEPCAPS: %m\n");
+               return r;
+       }
+
+       // Set capabilities
+       r = pakfire_jail_set_capabilities(jail);
+       if (r)
+               return r;
+
+       // Show capabilities
+       r = pakfire_jail_show_capabilities(jail);
        if (r)
                return r;