execute: when we run as PID 1 the kernel doesn't give us CAP_SETPCAP by default. Get that temporarily when dropping capabilities for good

This commit is contained in:
Lennart Poettering 2011-04-19 06:06:41 +02:00
parent 8024c3a71a
commit 73090dc815
2 changed files with 77 additions and 7 deletions

11
TODO
View File

@ -32,8 +32,16 @@ F15:
* don't trim empty cgroups
https://bugzilla.redhat.com/show_bug.cgi?id=678555
* drop cap bounding set in logger, hostnamed, readahead, ...
* timeout value is incorrectly parsed in /etc/fstab
Features:
* Add ListenSpecial to .socket units for /proc/kmsg and similar friends?
* avoid DefaultStandardOutput=syslog to have any effect on StandardInput=socket services
* use pivot_root on shutdown so that we can unmount the root directory.
* fix alsa mixer restore to not print error when no config is stored
@ -43,8 +51,11 @@ Features:
* write blog stories about:
- enabling dbus services
- status update
- the new configuration files
- you are a distro: why switch?
* maybe add tiny dbus services similar to hostnamed for locale?
* allow port = 0 in .socket units
* rename systemd-logger to systemd-stdio-syslog-bridge

View File

@ -904,6 +904,68 @@ fail:
}
#endif
static int do_capability_bounding_set_drop(uint64_t drop) {
unsigned long i;
cap_t old_cap = NULL, new_cap = NULL;
cap_flag_value_t fv;
int r;
/* If we are run as PID 1 we will lack CAP_SETPCAP by default
* in the effective set (yes, the kernel drops that when
* executing init!), so get it back temporarily so that we can
* call PR_CAPBSET_DROP. */
old_cap = cap_get_proc();
if (!old_cap)
return -errno;
if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) {
r = -errno;
goto finish;
}
if (fv != CAP_SET) {
static const cap_value_t v = CAP_SETPCAP;
new_cap = cap_dup(old_cap);
if (!new_cap) {
r = -errno;
goto finish;
}
if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) {
r = -errno;
goto finish;
}
if (cap_set_proc(new_cap) < 0) {
r = -errno;
goto finish;
}
}
for (i = 0; i <= CAP_LAST_CAP; i++)
if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
if (prctl(PR_CAPBSET_DROP, i) < 0) {
r = -errno;
goto finish;
}
}
r = 0;
finish:
if (new_cap)
cap_free(new_cap);
if (old_cap) {
cap_set_proc(old_cap);
cap_free(old_cap);
}
return r;
}
int exec_spawn(ExecCommand *command,
char **argv,
const ExecContext *context,
@ -1251,13 +1313,10 @@ int exec_spawn(ExecCommand *command,
}
if (context->capability_bounding_set_drop)
for (i = 0; i <= CAP_LAST_CAP; i++)
if (context->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) i)) {
if (prctl(PR_CAPBSET_DROP, i) < 0) {
r = EXIT_CAPABILITIES;
goto fail_child;
}
}
if (do_capability_bounding_set_drop(context->capability_bounding_set_drop) < 0) {
r = EXIT_CAPABILITIES;
goto fail_child;
}
if (context->user)
if (enforce_user(context, uid) < 0) {