From e6791c52f085b32592b670a94dfb71178103fd95 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Wed, 21 Jun 2023 15:25:19 +0000 Subject: [PATCH] jail: Don't drop any capabilities 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 --- src/libpakfire/jail.c | 197 ++++++++++++++++++++++++++---------------- 1 file changed, 121 insertions(+), 76 deletions(-) diff --git a/src/libpakfire/jail.c b/src/libpakfire/jail.c index c3a864f19..a7f22b5fb 100644 --- a/src/libpakfire/jail.c +++ b/src/libpakfire/jail.c @@ -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; -- 2.47.3