// HACKER NEWS — CYBERSECURITY
Software Sandboxing: The Basics
Diving into the territory of software sandboxing is diving into mostly uncharted
territory. The necessary pieces to implement good sandboxing in your software
are scattered all-around and the pioneers haven’t yet gathered enough knowledge
into an unified mappa mundi that can guide new sailors through some well
understood safe routes. In this blog post I’ll offer my own share of experiences
that I have acquired while working on sandboxing support for Emilua. Writing
style will suffer a little because I’ll err on the side of repeating myself too
much to avoid any misunderstandings.
First, let’s get some informal (but useful) definition for sandboxing just to
make sure we’re on the same page. Here’s
the
definition that was used by Julien Tinnes and Chris Evans at Hack In The Box
Malaysia 2009:
That’s a very good definition to keep the ball rolling. Let’s quickly iterate
over each point individually to make them crystal clear. However keep in mind
that the opinions I possess today are a little different from the
opinions J. Tinnes and C. Evans had during the 2009 talk (especially around “is
it okay to use superuser APIs?”), so my explanations will differ a little and
guide you towards what I consider better practices for 2025.
OSes present different interfaces to users and software developers. System
administrators traditionally rely on filesystem permissions to isolate services
(UNIX daemons). If we allowed third-party programs to freely change such
permissions then it’d nullify the policies the sysadmin was trying to enforce to
begin with.
Furthermore third-party programs abstract their own virtual worlds and most of
the time UNIX filesystem permissions aren’t a good fit to model the security
policies such other virtual worlds require. Do you use UNIX permission modes to
define who can see your Twitter feed or message you on Identi.ca? Filesystem
permissions aren’t the only knobs sysadmins possess to restrict access rights,
but the reasoning developed here also apply to these other knobs.
Nonetheless a process inevitably runs on top of an OS and there are
kernel-exposed resources the process interacts with (e.g. files). It’s this
interface that matters to the software developer. Web browsers such as Firefox
run DRM plugins and it’s desirable to run such third-party plugins without
allowing them to have full access to every file that Firefox has access to
(usually every file in the user’s HOME directory). Traditional tools such as
setuidgid can’t help here and their usefulness is limited as interfaces
sysadmins turn to. setuidgid and similar tools aren’t interfaces intended for
the software developer to use.
For programmatic privilege dropping, traditional UNIX interfaces are a poor
match, and OSes where this gap actually matters will provide extended interfaces
that go beyond traditional UNIX (e.g. FreeBSD’s Capsicum and Linux’s Seccomp).
When good interfaces for sandboxing weren’t available, programmers found their
way to create sandboxes anyway by abusing mechanisms available only to the
superuser. The most emblematic technique in this class is a helper suid binary
that’ll configure a chroot jail.
The obvious problem with these approaches is that they aren’t available to all
programs. Allowing any program to install suid binaries defeat any security
measures. Suid binaries equal to temporally raising privileges to full
administrative authority over the system. Privileges should only ever decrease,
never increase (principle of least privilege).
Another related concern here is to not design APIs that backfire by
exponentially increasing the kernel attack surface. The Docker boom popularized
Linux namespaces as a mechanism to cheaply isolate services. However within a
nested user namespace, the process runs as superuser (within that namespace),
and code paths within the kernel that would normally only be available to the
superuser are now available to every user. We have over a decade of kernel code
that was never writte