]> git.ipfire.org Git - pakfire.git/commitdiff
execute: Drop capabilities
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 20 May 2022 18:43:33 +0000 (18:43 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 20 May 2022 18:43:33 +0000 (18:43 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
configure.ac
src/libpakfire/execute.c

index 2632006f8f85ec2fbe410c1574eb50dc44604cf4..20f06cd15faaf6053c4de50fc76bd63de37874bb 100644 (file)
@@ -162,6 +162,7 @@ AC_CHECK_HEADERS([ \
        grp.h \
        libgen.h \
        libintl.h \
+       linux/capability.h \
        linux/limits.h \
        linux/magic.h \
        linux/sched.h \
@@ -176,11 +177,13 @@ AC_CHECK_HEADERS([ \
        stdlib.h \
        string.h \
        syslog.h \
+       sys/capability.h \
        sys/epoll.h \
        sys/file.h \
        sys/ioctl.h \
        sys/mount.h \
        sys/personality.h \
+       sys/prctl.h \
        sys/random.h \
        sys/resource.h \
        sys/sendfile.h \
@@ -211,6 +214,7 @@ AC_CHECK_FUNCS([ \
        nftw \
        openlog \
        personality \
+       prctl \
        remove \
        secure_getenv \
        sendfile \
index 88d21dffa318b82139f1465efdf40a2df4c2e480..37262e60d8784c6bb7fc4b3c67afbe301bb42fe7 100644 (file)
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/capability.h>
 #include <linux/limits.h>
 #include <linux/sched.h>
 #include <sched.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/capability.h>
 #include <sys/epoll.h>
 #include <sys/personality.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 #include <sys/user.h>
 #include <sys/wait.h>
@@ -323,6 +326,118 @@ int pakfire_execute_capture_stdout_to_array(struct pakfire* pakfire, void* data,
        return default_logging_callback(pakfire, NULL, priority, line, length);
 }
 
+static int pakfire_drop_capabilities(struct pakfire* pakfire) {
+       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,
+
+               // Deny opening files by inode number (open_by_handle_at)
+               CAP_DAC_READ_SEARCH,
+
+               // Deny setting SUID bits
+               CAP_FSETID,
+
+               // Deny locking more memory
+               CAP_IPC_LOCK,
+
+               // Deny modifying any Apparmor/SELinux/SMACK configuration
+               CAP_MAC_ADMIN,
+               CAP_MAC_OVERRIDE,
+
+               // Deny creating any special devices
+               CAP_MKNOD,
+
+               // Deny setting any capabilities
+               CAP_SETFCAP,
+
+               // Deny reading from syslog
+               CAP_SYSLOG,
+
+               // Deny any admin actions (mount, sethostname, ...)
+               CAP_SYS_ADMIN,
+
+               // Deny rebooting the system
+               CAP_SYS_BOOT,
+
+               // Deny loading kernel modules
+               CAP_SYS_MODULE,
+
+               // Deny setting nice level
+               CAP_SYS_NICE,
+
+               // Deny access to /proc/kcore, /dev/mem, /dev/kmem
+               CAP_SYS_RAWIO,
+
+               // Deny circumventing any resource limits
+               CAP_SYS_RESOURCE,
+
+               // Deny setting the system time
+               CAP_SYS_TIME,
+
+               // Deny playing with suspend
+               CAP_WAKE_ALARM,
+
+               0,
+       };
+
+       size_t num_caps = 0;
+       int r;
+
+       // Drop any capabilities
+       for (const int* cap = capabilities; *cap; cap++) {
+               r = prctl(PR_CAPBSET_DROP, *cap, 0, 0, 0);
+               if (r) {
+                       ERROR(pakfire, "Could not drop capability %d: %m\n", *cap);
+                       return r;
+               }
+
+               num_caps++;
+       }
+
+       // Fetch any capabilities
+       cap_t caps = cap_get_proc();
+       if (!caps) {
+               ERROR(pakfire, "Could not read capabilities: %m\n");
+               return 1;
+       }
+
+       /*
+               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);
+       if (r) {
+               ERROR(pakfire, "cap_set_flag() failed: %m\n");
+               goto ERROR;
+       }
+
+       // Restore capabilities
+       r = cap_set_proc(caps);
+       if (r) {
+               ERROR(pakfire, "Could not restore capabilities: %m\n");
+               goto ERROR;
+       }
+
+ERROR:
+       if (caps)
+               cap_free(caps);
+
+       return r;
+}
+
 static int find_environ(struct pakfire_execute* env, const char* key) {
        if (!key) {
                errno = EINVAL;
@@ -437,6 +552,11 @@ static int pakfire_execute_fork(void* data) {
        if (r)
                return r;
 
+       // Drop capabilities
+       r = pakfire_drop_capabilities(pakfire);
+       if (r)
+               return r;
+
        // exec() command
        r = execvpe(env->argv[0], (char**)env->argv, env->envp);
        if (r < 0) {