As time goes on, I have become increasingly mistrustful of closed-source software. I have always been mistrustful of crypto that the authors won't talk about. Therefore I decided that, while I do require[1] it for employment reasons from time to time, I am not interested in installing Microsoft's Skype client on my new Sputnik 3 laptop — at least, not directly.
My first inclination was to put the whole ball of wax in a virtual machine; after all, when I provisioned the disk I left a substantial amount of room just for development VMs — why not one for untrusted software, too? Unfortunately, some digging for information and hacking at the issue indicated that it wasn't going to be that easy, at least not with a KVM partition. To make a long story short, emulated sound hardware isn't really a working thing in Ubuntu 12.04 (the distribution presently on my laptop for various reasons, some of which are detailed here). That left me with two possibilities: 1) chase a network audio solution, or 2) find a different way to sandbox Skype. I've done my share of playing with network audio solutions over the years, and let's just say that I wasn't looking forward to doing it again; therefore, new sandbox it was.
A chroot jail seemed like the next best choice, after a dedicated VM fell down. The isolation between a chrooted application and the host operating system is not nearly as good, particularly after riddling the chroot with holes for sound and graphics, but I felt like I could mitigate the worst of the exposed surface area. So I set about doing so, and in the process built a set of scripts and a chroot configuration for a (relatively) efficient audio-enabled sandbox for untrusted or semi-trusted applications. At the moment, mine runs Skype. This document describes how I set it up. There is nothing here that isn't documented somewhere else, but I couldn't find it all scraped up in a pile, so here it is.
Setting up a minimal chroot
Building chroots in Debian-based distributions is refreshingly easy. Several tools are provided for both managing a chroot environment and creating an installation with the required dependencies for a particular package set. For this task, I used schroot and debootstrap. The former manages the chroot environment itself, while the latter handles packaging for a minimal (or not so minimal, in this case!) internally-consistent environment.
The first thing to take care of is installing a complete enough set of packages that the chroot jail can manage itself from there on out. To do this, pick where you want to put your chroot (I used /mnt/unsafe/, and that's the path I'll be using throughout the rest of this document; adjust accordingly for your own purposes) and initialize it with debootstrap. In this case, I chose an i386 Ubuntu 12.04 (“precise”) jail, and initialized it as follows:
sudo debootstrap --arch=i386 precise /mnt/unsafe/ http://archive.ubuntu.com/ubuntu
Documentation for how to use debootstrap effectively is readily available, so I won't cover it further in this document.
The next step is to turn this set of extracted packages into an actual chroot jail; as previously mentioned, I used schroot to accomplish that. It handles setup that requires superuser privileges, including mounting special filesystems such as /proc, and jail lifetimes. In order to jail Skype as tightly as possible while still allowing it access to my session PulseAudio server for sound, I needed a jail that was slightly more permissive than its minimal configuration, but far less permissive than its default configuration — which mounts user home directories inside the jail, even! I chose to create a configuration called unsafe that mounts the necessary files, but not a complete /home, and does not copy over unnecessary user or password database information.
The configuration for such a jail consists of four files in a directory under /etc/schroot (in this case, /etc/schroot/unsafe), two of which (copyfiles and nssdatabases are empty. You can download a tarball containing the setup I used, though it will require some editing, but I will include descriptions of the other two files here.
The first is config, and it is simply a shell script fragment describing the location of the other files. Mine looks like this:
# Filesystems to mount inside the chroot. FSTAB="/etc/schroot/unsafe/fstab" # Files to copy from the host system into the chroot. COPYFILES="/etc/schroot/unsafe/copyfiles" # System NSS databases to copy into the chroot. NSSDATABASES="/etc/schroot/unsafe/nssdatabases"
The second is a description of the filesystems to be mounted onto the chroot, in fstab(5) syntax. In this case, the entries are all bind mounts, and there are two extra mounts that won't appear in most chroots: /home/elb/.pulse and /var/lib/dbus. These directories are required to get PulseAudio connectivity into the chroot, and they are helpfully documented in the PulseAudio FAQ. The complete fstab for my setup is:
/proc /proc none rw,bind 0 0 /sys /sys none rw,bind 0 0 /tmp /tmp none rw,bind 0 0 /run/shm /run/shm none rw,bind 0 0 /home/elb/.pulse /home/elb/.pulse none rw,bind 0 0 /var/lib/dbus /var/lib/dbus none rw,bind 0 0
Having established the configuration to be used for the chroot, we now have to bind it to the chroot directory and determine who can use it. This is done in the file /etc/schroot/schroot.conf, which uses a syntax reminiscent of Windows .ini files. To configure this particular chroot, I used this stanza:
[unsafe-i386] type=directory directory=/mnt/unsafe description=Precise chroot for i386 untrusted binaries script-config=unsafe/config personality=linux32 users=elb
This instructs schroot to create a jail called unsafe-i386 using the unsafe scripts we created earlier on a jail located at /mnt/unsafe containing an i386 distribution, and to allow the user elb to create and enter the jail without superuser privileges.
The last step is to create a home directory on the chroot, and add a user account to its /etc/passwd and /etc/group databases. You can probably accomplish this by the following (basically what I did), but you will want to double-check the results; in particular, assuming that the current user's primary GID is the same as the UID is not so portable (but will work on most standalone Ubuntu installs):
sudo mkdir -p /mnt/unsafe/home/$USER sudo chown $USER:$USER /mnt/unsafe/home/$USER sudo echo "$USER:x:$UID:$UID:,,,:/home/$USER:/bin/bash" >> /mnt/unsafe/etc/passwd sudo echo "$USER:x:$UID:" >> /mnt/unsafe/etc/group
Buffering X11 access
An application with direct access to your X11 server can do all kinds of mean, nasty, ugly things to you, particularly if it belongs on the Group W bench like Skype. These things range from sniffing your keystrokes to bypassing your screen lock to who knows what else. Unfortunately, we have to provide the jail with access to several things we would rather not (like /tmp, the PulseAudio socket, and — possibly most unfortunately — dbus), but that doesn't mean we have to give it direct access to X11.
Enter Xpra. Xpra is what the maintainers describe as “screen for X,“ providing detachable sessions and window forwarding over the network via an efficient, rootless protocol. In this case, however, we're not as concerned about that as the fact that Xpra uses its own headless X server and proxies actual windowing information between the client and your server. The actual extent to which this will protect you from client badness isn't clear to me, but it's a start. I need to do more research on this point — as well as into the possibility of using a newer release of Xpra to handle this whole shebang from a VM using PulseAudio.
To get the Ubuntu packages for Xpra, we have to add Universe to the chroot package system. In order to do that, edit (as root) /mnt/unsafe/etc/apt/sources.list and add the word universe to the end of the Precise sources line. It should look like this:
deb http://archive.ubuntu.com/ubuntu precise main universe
Having done that, enter the chroot jail as root and install the package and its prerequisites:
sudo schroot -c unsafe-i386 apt-get update apt-get install xpra
Note that the two commands from within the jail don't need a sudo prefix, as you're already root. Be sure to exit the jail when you're done.
The final step in walling the jail away from your local X11 server is to revoke its access to the server socket in /tmp. By default, most modern Linux distributions use a magic xhost property that allows all local processes owned by the same user as the X11 server to access the server without other authentication credentials. Since the chroot jail has direct access to the server socket, we want to prevent that. You can see the permission for this by running xhost. If something like this shows up, local user access is enabled:
access control enabled, only authorized clients can connect SI:localuser:elb
The second line is the important one — you should always see the first! That access will need to be revoked to prevent jailed applications from accessing your X11 server directly whether you want them to or not. The command to do so is xhost -SI:localuser:$USER, but if you use the scripts linked later on this page they will handle it for you.
Configuring the jail for Skype
Having created the jail, we now want to set it up for Skype. Since I elected to handle most of the getting in and out of the jail tasks external to the jail (more on that later), that basically means two steps: fetching and installing Skype's prerequisites, and installing Skype itself.
I downloaded the Skype package for my distribution, placed it in the /tmp directory for the chroot, then entered the chroot as root to install the dependencies and then the package itself:
sudo schroot -c unsafe-i386 apt-get install libqtgui4 libasound2-plugins libxss1 libxv1 libqtwebkit4 dpkg -i /tmp/skype-ubuntu-precise_4.2.0.13-1_i386.deb
The above prerequisite list was complete for me, but if things change it may become stale. Fortunately, the package management system handles this (relatively) gracefully. If the dpkg command fails, simply run apt-get install -f to have it patch up the necessary dependencies, then re-run dpkg.
Gluing it all together
Once all of this is in place, the key is gluing it all together to minimize the pain of working across the jail interface. I have created a set of scripts to manage the jail. They handle starting the jail, starting the Xpra server on the jail side and the Xpra client on the local side, plumbing apps through Xpra, and shutting the jail down when you're done. I am not going to document how they work, and if they break you can keep both pieces — but they're working for me, and I'd be happy to answer specific questions.
The poor man's guide to setting them up is this: Copy start-unsafe, stop-unsafe, and unsafe-exec to somewhere in your path on the host machine. Put withxpra in the chroot jail in ~/bin (specifically — not just in the path!). Then, run a jailed GUI command as unsafe-exec <command>. For skype, that's unsafe-exec skype.
Final words
This isn't an ideal solution. I don't like the (lack of) isolation it provides. It allows audio, but not video. It's unclear exactly how much trouble Skype can get into through the xpra connection. (Something like ssh -X would be more clear.) I strongly believe that a determined attacker could bust out of this chroot more or less immediately. Don't trust your familyl jewels to this solution! However, I also believe that it will protect the host machine from casual abuses of by the jailed software, and that it provides some measure of isolation in the event that the jailed software has dangerous bugs.
Running a parallel OS in VMware or some other audio-capable virtualization solution would be better. Avoiding ugly proprietary software like Skype would be even better yet.
Finally, note that sound propagation with this solution only works with clients that use PulseAudio. That will cover a lot of clients, but not everything.
[1] This is, of course, an exaggeration. I do not require it for employment, and were my convictions a bit stronger, I could almost certainly get away from it entirely. The effort of doing so, however, is somewhat higher than the effort of building a chroot jail plus my mistrust. Or so it turns out.