Masochism never ends — Some improvements for Gentoo safety

Those of you who follow my blog for a long time might have already guessed what I’m going to talk about at this point: PAM. Each and every time I end up working on PAM I remind myself I’m probably a masochist in the deep of my soul, which is pretty bad by itself. I have to clear up though, that I’m not in the same rank as Max Mosley and that my masochism stop at maintaining packages that are ridiculously left alone by anybody else. Just to be safe, okay?

So what’s up in PAM land? Well, there are currently two things I’m experimenting with that I would like to see in our default PAM setup (through pambase) in the next months: capabilities and namespaces.

I already wrote something about capabilities in February 2008, but I never went around making sure it worked like it should. Right now I haven’t really even started the work to support that, but I really intend to get this working before the end of the year. This would complement eventual support for filesystem-based capabilities in Portage that I’ve already proposed a few times before. I got interested again in implementing that after reading that Fedora 12 is also doing so and that it would have solved the recent PulseAudio vulnerability (which luckily we addressed right away in another way).

For what concerns namespaces, instead, this is not only a security issue that I’m investigating but also a possible system setup improvement that could really be something. You might remember that some time ago I made it possible to quickly support pam_mktemp which creates per-user temporary directories in /tmp and make them inaccessible from other users.

Unfortunately there have been, with time, quite a few problems related to that functionality: at the time, start-stop-daemon in OpenRC didn’t really set up environment properly (and I think the same is also true for the version bundled with baselayout1), which in turn created problems to me and others using the daemon mode of emacs because it used the temporary directory to create a listening socket for the client to connect (and daemon and user ended up having different temporary directories). Nowadays, with the working command, and services using pam_mktemp, the problem appears with Samba: when starting Samba on a system set up with pam_mktemp, logging into shares that have usernames and passwords fail because Samba tries to use the user-defined temporary directory as the user “nobody” (which does not have the privilege to access that). Finally, lots of packages simply ignore the TMPDIR variable, either because they “want consistency” or because, like it’s the case for gnupg, upstream has no clue about Unix sockets and expects TMPDIR to mock stuff up via network, thus ignores it (breaching the GNU coding style guidelines, by the way).

So I decided to go with the alternative way, which is not supported on non-Linux systems (thus pam_mktemp is not going to die just yet), but is also available off the shelf on the Linux-PAM package: pam_namespace and polyinstantiated directories. To cut the story short and make it understandable to users, it simply means that once it’s set up, /tmp as seen by different users is a different directory altogether.

I’m still not sure if this is the way to go to be honest. When I first looked into it, it would break postgres, because the older settings would use /tmp to store the connection socket rather than /var/run; I also am not sure whether it’s totally fine in respect to security: since I usually start my services sudo’ing from my user, the directories used for polyinstantiation have “flame” as group; of course I cannot access them because I cannot access the base directory, but still… Also, this method seems to break the tramp feature of Emacs that allows to edit root-owned files from within an user session (it assumes that /tmp is always the same between users afaics).

Now, I said that namespaces are not only a security feature but can also help with configuration; some time ago I tried finding an easy way to set the XDG_CACHE_DIR variable for users so that instead of saving in ~/.cache it would use /var/cache (reason for this is that the home file system is usually smaller and should not be wasted for cache – in my case it’s also under RAID – while the /var/cache file system can just be cleaned up as needed). Unfortunately, our env-update command does not take it gently if hte $USER variable is used to define another variable, so I gave up. With pam_namespace, it would be possible to have a /var/cache/user directory that is an instance of /var/cache/users/$USER, and then have XDG_CACHE_DIR to use that directory. Similarly we could do that for /var/run/user so that local instance sockets are saved there rather than in /tmp (or /home) where they don’t belong.

So this is what is boiling in the PAM pot for the next months; you can always speed it up at your pleasure.

Capabilities and PAM

Most of our current ~arch users most likely noticed an update in libcap to version 2. They noticed because it had some conflicts on the first revision out there and thus crapped out after build. Not much of a problem though, it’s now fixed.

Interstingly, libcap 2 has a pam USE flag that should build a pam_cap PAM module that allows you to set stuff via PAM, akin to the way it’s already possible to set limits through pam_limits. Unfortunately it did not install it, so it was quite useless.

But fear not, 2.06-r1 now installs the PAM module, and the configuration file, so it’s now possible to use it. Unfortunately it doesn’t seem to work.

For those of you who don’t know what capabilities are, they are a way to provide an user, a file, a process with some privileges (capabilities) that would otherwise be limited to root, without having to provide the full blown root privileges. It’s a way to tighten security: you allow a process (or user, or file) just to do what it has to do.

The usual way that capabilities are used, up to now, is to use libcap in setuid root programs: the program starts, uses libcap to get itself just the capabilities it needs, and then it drops root privileges, keeping just what it really needs. This is what PulseAudio does for instance, as well as the setuid root helper of wireshark. This allows to tighten a bit the security, but only works with setuid root programs, which requires thus to lax security, although for a limited time (a code execution after the root privileges are dropped is less dangerous, but there is still a chance that there is exploitable code before they are dropped).

Since kernel 2.6.24, it’s finally possible to set capabilities on files (without kernel patches at least, I think there were enough laying around before to do that), this means you can replace a setuid root program with a capability-set program. Let’s take for instance the ping command. A very basic command. On a default system, ping is setuid root:

-rws--x--x 1 root root 35480 Nov 12 17:26 /bin/ping

After launching it and setting up to be able to access RAW sockets, the privileges are tuned down to the actual user calling ping. It works, it reduces the risk, but using capabilities it should be even simpler:

flame@enterprise ~ % ls -l /bin/ping
-rwx--x--x 1 root root 38256 26 gen 13:15 /bin/ping
flame@enterprise ~ % /sbin/getcap /bin/ping
/bin/ping = cap_net_raw+ep
flame@enterprise ~ % ping -c1 localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.028 ms

--- localhost ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.028/0.028/0.028/0.000 ms

Interesting, isn’t it? The ping command is no more setuid, there is no need to drop privileges as it only has the privileges it needs: access to the raw socket.

This works nice for stuff like ping and other network commands, and for sniffers, although it works for all the users in the system, so while it replaces well the setuid root executables, it doesn’t work well to give generic capabilities to programs. For instance you might not want all users access to sniffers, so instead of giving the RAW access to the sniffer files (and then setting groups like it’s done now for wireshark) you would probably prefer to give RAW access to a particular user, which could then do whatever she wants with sniffing software.

This is the idea behind pam_cap: you get a capability.conf file, similar to limits.conf, that allows you to give particular capabilities to particular users, rather than executables. Unfortunately it doesn’t seem to work here. Even setting it up properly, it seems to be plainly ignored. If I don’t give ping the file capabilities for RAW packets, it doesn’t work, even if my processes have inheritable RAW capabilities. I’ll have to dig up a bit on this.

Anyway, now that we have a nice implementation with PAM, and file-based access, I hope the future will see us moving toward more tight security by using file-based capabilities rather than setuid root programs. I’m now planning how to handle capabilities in PAM in an easy way for users… you’ll see more blogs on the matter in the next weeks.