Hello,

I am running latest pulseaudio from git master as of this morning, and
had some problems with system-wide mode (running as pulse user). I
suspect this is due to my recent kernel, but it could also be the way
Ubuntu is configured.

The observed behavior (thanks, strace!) is that the library functions
setgroups, setresgid, etc. all fail in main.c... this is because we
call pa_drop_caps() fairly early on (after setting RT_PRIO) which
removes our CAP_SETGID and CAP_SETUID capabilities. On my system, at
least, without these capabilities, the above-mentioned syscalls fail,
resulting in numerous errors on startup. I'm using Ubuntu Intrepid
Alpha2, which is a 2.6.26 kernel.

I have created a pretty straightforward patch to src/daemon/main.c,
src/daemon/caps.h and src/daemon/caps.c which does the following:

1. New function, pa_retain_caps, in caps.h. Drops all caps except
certain ones specified in a cap_value_t array. Heavily inspired by
pa_limit_caps itself, but I didn't want to break pa_limit_caps, which
has the pre-set behavior of retaining *only* CAP_SYS_NICE.

2. Use pa_retain_caps -- keeping CAP_SETGID and CAP_SETUID, but
getting rid of CAP_SYS_NICE -- after acquiring RT_PRIO.

3. Finally, we drop *all* caps (including CAP_SETGID and CAP_SETUID)
at the end of the change_user() function. change_user() is called
chronologically after pa_retain_caps, so on Linux, the capabilities we
have (if we run as root) funnel down thusly during startup:

all caps --> CAP_SYS_NICE --> CAP_SETGID / CAP_SETUID --> no caps

Startup time does not seem negatively affected (on a desktop, what's a
few syscalls? ;)) by the additional transition. Since this all seems
very Linux-specific, I was careful to make this entire patch invisible
to people who don't run Linux or whose userspace Linux headers don't
have the capabilities interface. This definitely deserves testing on
older kernels, but I don't have any available at the moment. On my
system, though, this patch does not generate any further bad-looking
warnings/infos from PA... it seems to work well now.

Also, there was a slight problem which I'm just going to complain
about but not patch ;) It may have been related to this, not sure...
my first roadblock was it was trying to mkdir /var/lib/pulse and set
its permissions to 0700. I was making the directory as root and
chown-ing it to pulse:pulse, but PA got angry and unlinked it each
time, until I figured out (from strace) that it wants it 0700 or it
will delete it. ;-)

So, to anyone having trouble with /var/lib/pulse when running
system-wide: the fix is

# mkdir -m 0700 /var/lib/pulse
# chown pulse:pulse /var/lib/pulse
# pulseaudio

Thanks,

Sean
diff --git a/src/daemon/caps.c b/src/daemon/caps.c
index ae07119..cbfbbff 100644
--- a/src/daemon/caps.c
+++ b/src/daemon/caps.c
@@ -82,6 +82,23 @@ void pa_drop_root(void) {
 
 #if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H)
 
+void pa_retain_caps(cap_value_t *in_caps, int numcaps)
+{
+	cap_t caps;
+	
+	pa_assert_se(caps = cap_init());
+	pa_assert_se(cap_clear(caps) == 0);
+	pa_assert_se(cap_set_flag(caps, CAP_EFFECTIVE, numcaps, in_caps, CAP_SET) == 0);
+	pa_assert_se(cap_set_flag(caps, CAP_PERMITTED, numcaps, in_caps, CAP_SET) == 0);
+
+	if (cap_set_proc(caps) < 0)
+		pa_drop_caps();
+
+    pa_assert_se(cap_free(caps) == 0);
+
+    pa_assert_se(prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == 0);
+}
+
 /* Limit permitted capabilities set to CAPSYS_NICE */
 void pa_limit_caps(void) {
     cap_t caps;
diff --git a/src/daemon/caps.h b/src/daemon/caps.h
index 176aa90..0fe340e 100644
--- a/src/daemon/caps.h
+++ b/src/daemon/caps.h
@@ -23,10 +23,12 @@
 ***/
 
 #include <pulsecore/macro.h>
+#include <sys/capability.h>
 
 void pa_drop_root(void);
 void pa_drop_caps(void);
 void pa_limit_caps(void);
+void pa_retain_caps(cap_value_t*, int);
 pa_bool_t pa_have_caps(void);
 
 #endif
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 1459441..7b09ad7 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -40,6 +40,10 @@
 
 #include <liboil/liboil.h>
 
+#ifdef _LINUX_CAPABILITY_H
+#include <linux/capability.h>
+#endif
+
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
@@ -258,6 +262,9 @@ static int change_user(void) {
 
     pa_log_info("Successfully dropped root privileges.");
 
+    /*We still have CAP_SETUID and CAP_SETGID to get rid of*/
+    pa_drop_caps();
+
     return 0;
 }
 
@@ -346,6 +353,14 @@ int main(int argc, char *argv[]) {
 #endif
     char *lf = NULL;
     int autospawn_lock_fd = -1;
+#ifdef _LINUX_CAPABILITY_H
+    static cap_value_t setuid_caps[2] =
+    {
+	CAP_SETUID,
+	CAP_SETGID
+    };
+#endif
+
 
 #if defined(__linux__) && defined(__OPTIMIZE__)
     /*
@@ -527,7 +542,11 @@ int main(int argc, char *argv[]) {
 
         if (drop)  {
             pa_log_info("Giving up CAP_NICE");
-            pa_drop_caps();
+	    #ifdef _LINUX_CAPABILITY_H
+		    pa_retain_caps(setuid_caps, 2);
+	    #else
+		    pa_drop_caps();
+	    #endif
             suid_root = FALSE;
         }
     }
_______________________________________________
pulseaudio-discuss mailing list
[email protected]
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss

Reply via email to