From 4d88fcd59da84ac4f09113855c8f15384a4e05c3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 25 May 2007 20:35:30 +0000 Subject: when called with the setid bit change euid to uid sooner to make sure that we can access our own files even when we dropped most capabilities. (Closes #21) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1455 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/daemon/caps.c | 33 +++++++++++++++------------------ src/daemon/main.c | 29 ++++++++++++++++++----------- src/pulsecore/core-util.c | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 2ea51c9f..8043230c 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -35,6 +35,9 @@ #ifdef HAVE_SYS_CAPABILITY_H #include #endif +#ifdef HAVE_SYS_PRCTL_H +#include +#endif #include @@ -76,35 +79,31 @@ void pa_drop_root(void) { #endif -#ifdef HAVE_SYS_CAPABILITY_H +#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H) -/* Limit capabilities set to CAPSYS_NICE */ +/* Limit permitted capabilities set to CAPSYS_NICE */ int pa_limit_caps(void) { int r = -1; cap_t caps; cap_value_t nice_cap = CAP_SYS_NICE; - /* Only drop caps when called SUID */ - if (getuid() == 0) - return 0; - caps = cap_init(); assert(caps); - cap_clear(caps); - - cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET); if (cap_set_proc(caps) < 0) goto fail; + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) + goto fail; + pa_log_info("dropped capabilities successfully."); - - r = 0; + + r = 1; fail: - cap_free (caps); + cap_free(caps); return r; } @@ -114,24 +113,22 @@ int pa_drop_caps(void) { cap_t caps; int r = -1; - /* Only drop caps when called SUID */ - if (getuid() == 0) - return 0; - caps = cap_init(); assert(caps); cap_clear(caps); + prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0); + if (cap_set_proc(caps) < 0) { pa_log("failed to drop capabilities: %s", pa_cstrerror(errno)); goto fail; } - + r = 0; fail: - cap_free (caps); + cap_free(caps); return r; } diff --git a/src/daemon/main.c b/src/daemon/main.c index 211dd30c..72e47975 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -329,22 +329,29 @@ int main(int argc, char *argv[]) { struct timeval tv; #endif - setlocale(LC_ALL, ""); - - pa_limit_caps(); - #ifdef HAVE_GETUID real_root = getuid() == 0; suid_root = !real_root && geteuid() == 0; +#else + real_root = 0; + suid_root = 0; +#endif + + if (suid_root) { + if (pa_limit_caps() > 0) + /* We managed to drop capabilities except the needed + * ones. Hence we can drop the uid. */ + pa_drop_root(); + } + + setlocale(LC_ALL, ""); if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0 || gid >= 1000)) { pa_log_warn("WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'."); + pa_drop_caps(); pa_drop_root(); + suid_root = real_root = 0; } -#else - real_root = 0; - suid_root = 0; -#endif LTDL_SET_PRELOADED_SYMBOLS(); @@ -381,10 +388,10 @@ int main(int argc, char *argv[]) { if (conf->high_priority && conf->cmd == PA_CMD_DAEMON) pa_raise_priority(); - pa_drop_caps(); - - if (suid_root) + if (suid_root) { + pa_drop_caps(); pa_drop_root(); + } if (conf->dl_search_path) lt_dlsetsearchpath(conf->dl_search_path); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index cc0fb205..480ac3b7 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -51,6 +51,10 @@ #include #endif +#ifdef HAVE_SYS_CAPABILITY_H +#include +#endif + #ifdef HAVE_PTHREAD #include #endif @@ -481,7 +485,23 @@ char *pa_strlcpy(char *b, const char *s, size_t l) { sensible: set the nice level to -15 and enable realtime scheduling if supported.*/ void pa_raise_priority(void) { - +#if defined(HAVE_SYS_CAPABILITY_H) + cap_t caps; + + /* Temporarily acquire CAP_SYS_NICE in the effective set */ + if ((caps = cap_get_proc())) { + cap_t caps_new; + cap_value_t nice_cap = CAP_SYS_NICE; + + if ((caps_new = cap_dup(caps))) { + cap_set_flag(caps_new, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET); + cap_set_flag(caps_new, CAP_PERMITTED, 1, &nice_cap, CAP_SET); + cap_set_proc(caps_new); + cap_free(caps_new); + } + } +#endif + #ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) pa_log_warn("setpriority(): %s", pa_cstrerror(errno)); @@ -495,13 +515,13 @@ void pa_raise_priority(void) { if (sched_getparam(0, &sp) < 0) { pa_log("sched_getparam(): %s", pa_cstrerror(errno)); - return; + goto fail; } sp.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) { pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno)); - return; + goto fail; } pa_log_info("Successfully enabled SCHED_FIFO scheduling."); @@ -514,6 +534,16 @@ void pa_raise_priority(void) { else pa_log_info("Successfully gained high priority class."); #endif + +fail: + +#if defined(HAVE_SYS_CAPABILITY_H) + if (caps) { + /* Restore original caps */ + cap_set_proc(caps); + cap_free(caps); + } +#endif } /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ -- cgit