// 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);
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;