
Pledge() – a new mitigation mechanism in OpenBSD - acchan
http://www.openbsd.org/papers/hackfest2015-pledge/mgp00001.html
======
Animats
The problem with granular privileges is that programs want too many of them.
See any Android flashlight app. Theo is getting good results on tightening up
the classic UNIX command line tools. Has he tried EMACS yet?

Also, a bigger problem than system calls is what parts of the file system the
program can access. The concept that a program has all the privileges of its
owner is the biggest single problem with permissions.

What might work is having a few general classes of programs, with appropriate
restrictions. Consider, for example, permission set "game, single player":

\- Can read anything in its install package. \- Can read/write only to working
directory associated with product/user combination. \- Can go full screen, use
audio output (not microphone), access mouse/touch, etc.

That seems reasonable. Angry Birds could run under those restrictions. For
some games, the DRM won't work, the anti-cheating won't work, the ads won't
work, the in-game purchasing won't work, the updater won't work, and the
social leader board won't work. Still, it would be reasonable to require in an
app store that games still work locked down to that level, even if some
features are disabled.

One way an app store might make this work is that programs which require very
limited permissions are easy to get into the store. Programs which require
extensive permissions go into the "adults only" section of the store, or have
to go through a source code audit at the developer's expense.

~~~
pjmlp
Hence why I am a supporter that Apple and Microsoft keep pushing their
sandboxing approaches, even with developers screaming along the way.

Eventually we will get it right, because Theo is right, normal people will
just disable security, because it is an hassle on their eyes.

One just needs to search the online forums for people asking how to run as
root on Mac OS X or Windows.

~~~
mtgx
Exactly why I hate the argument that goes along the lines of "if people
disable it, they must not want security!" \- or if people buy cheap phones,
they must not want it either - and so on.

The people are not at fault, and they don't know about these things. When the
security is bad, it's a _design problem_ \- therefore, it's the
system/platform/app developer's fault (although app developers are much less
at fault than the platform developers, since they can also only control what's
given to them by the platform vendor).

~~~
pjc50
I think there's a slide to that effect in this presentation: that the
development process involves upgrading the apps to the point at which the
security can be made mandatory.

------
kentonv
Sounds like this could be implemented on Linux as a library on top of seccomp.

I'm not impressed by De Raadt's objection to seccomp. BPF programs may
technically be turing-complete, but most of the things pledge() does can be
implemented by a pretty simple seccomp filter that's just a flat list of
conditionals implementing a whitelist or blacklist.

Meanwhile De Raadt points out, correctly, that voluntary security mechanisms
will be ignored by most developers... but pledge() appears to be voluntary.

Seccomp-bpf is often used by sandboxes like Chrome or Sandstorm.io (of which I
am lead developer), where it is _not_ voluntary for the code that ends up
being run inside the sandbox. But sandbox developers are likely to want
seccomp's customizeability over pledge's ease-of-use.

So while it's nice that that pledge() is so easy to use, it strikes me that
it's targeting the wrong audience with that design.

~~~
tedunangst
How does one whitelist open("/dev/null") with seccomp-bpf?

~~~
kentonv
I knew someone would ask that.

So, the way I'd recommend doing the filename whitelist is by setting up a
mount namespace. Create a tmpfs, create the necessary directory tree inside
it, bind-mount each whitelisted path in the tmpfs to the real file, then
pivot_root into the tmpfs. This sounds complicated but is actually not very
much code, and again a library could make it easier.

But I think you could also do it with pure seccomp. The trick is to copy the
filename list into memory pages that you subsequently mark read-only. Then,
have your seccomp filter whitelist specifically pointers to those strings, and
prohibit making the pages writable again.

(Disclaimer: I just came up with this on a whim, it probably needs more
thought.)

~~~
caf
You don't even have to copy the filenames around and mess with changing page
permissions - simply doing:

    
    
      static const char * const dev_null = "/dev/null";
    

and then whitelisting the pointer dev_null is sufficient, because string
literals are stored in the text section which is mapped read-only.

~~~
amluto
That only works if you've locked down mprotect, mmap, and munmap.

~~~
caf
Yes, the parent covered that.

------
friendzis
Well, I have always thought that the best way to solve such problems are
selective privileges. Android/iOS have privileges, though those are either all
or nothing. Desktop basically has root/non-root.

I think this problem should be solved not by the developer: I pledge to only
read files, but the user/administrator: you are only allowed to read files;
and attempts to do that could either fail hard on opening the file in rw mode,
or silently pipe data to /dev/null on writes.

As an added benefit this would teach programmers to actually expect calls to
fail and easily test that by applying restrictions. In such environments a
program could test its env during initialization and either refuse to start or
try to work in a limited fashion. Blowing up during runtime is better than
nothing, though still borderline acceptable. Yes, this helps catch misbehaving
programs and more importantly highly helps mitigate exploits (exploit
automagically runs in isolated jail).

Rachel by the Bay has awesome writing [1] on exactly this topic. Makes one
think: how many of us have encountered failed fork()/malloc()/fopen()/execve()
and are guilty of releasing buggy code, because "f it, highly unlikely, will
fix later"?

[1]:
[https://rachelbythebay.com/w/2014/08/19/fork/](https://rachelbythebay.com/w/2014/08/19/fork/)

~~~
illumen
Optional things for development are optional so won't always be used. I guess
rather than saying "this is a unix program" you could say, this is an OpenBSD
program. Which would mean that it has undergone a set of processes for
development where all the optional things are not turned off. For example:
code review, static analysis, fuzz/quickcheck style testing, using pledge()
appropriately, etc. But you'd need to define the set of processes that need to
be followed before it could be called an 'OpenBSD program'. Replace 'OpenBSD
program' with whatever you want to call this.

Who should set up the permissions? If you trust the developers, you trust them
to set up the permissions for you. However, what happens of you don't trust
them? You need administrators and users to be able to tweak what the programs
are allowed to do.

What is really great about doing it at the developer level is that the
administrator do not need to think about that stuff.

For large programs like emacs, or python, it is unfortunate that you can't
disable the privs just for a functional call for example. I'd like to see a
discussion on why this wouldn't work? I guess there is a good reason - but
they don't say.

If you "allow only these privs until Done" where Done would be defined by the
program jumping back to a point set by pledge() call. If the process does not
allow writing on executable memory this would work (at least for non jit
processes).

I wonder if there are ways this can be used by python. Perhaps using a fork
this could be done. The program forks to run just the priv bit of code. It can
use pledge() and drop all the stuff it doesn't need - do it's business - then
die.

~~~
vidarh
The "traditional" way of achieving something like this on Unix-like systems is
indeed to fork and use the various available mechanisms (different uid's,
chroot etc.) to reduce the attack surface but the problem is that it's a lot
of work and the classic API's leave you with relatively limited opportunities
to relinquish privileges.

Qmail is a good example of this philosophy: Many small binaries that isolate
different functionality and are run as different users and mostly communicate
via command line and pipes. It makes the attack surface small. But pledge()
could have made it even smaller.

------
badalex
For fun I made a perl web app use this. Much simpler than systace or seccomp.

I use the path argument as simple form of chroot(2). Previously I had to
create a vnd (think loopback device if you are coming from linux) to chroot
nicely. On code updates, some process had to rsync static assets into the
chroot (I preload all of the needed perl, then chroot()). On linux, the same
app uses containers/namespaces. Leveraging read only bind mounts for static
assets, seccomp, and various prctrl fiddling. All that ends up being a few
hundred lines of code. With pledge is really just a few lines to call the
syscall. Much easier to reason about.

Even if you end up having to allow most syscalls, the path argument alone IMHO
makes it worth it.

------
X-Istence
One of the first things that sysadmins at my last place of work would do is
turn off SELinux on new installs of RHEL.

There were too many times that SELinux would cause issues for them because
they didn't understand the built-in policies and where to place stuff. As a
security conscious person, it is a HUGE pain in the behind and I've spent many
hours debugging SELinux and it's policies.

~~~
INTPenis
That is unfortunately a bad practice but there also people out there who leave
it in enforcing mode and actually make an effort to use it.

I think selinux use has increased lately, at least from my perspective.

Where I work I am constantly forcing it on people and volunteer to solve any
problems they might have to ease their transition.

Just like pledge would require passionate developers who actually care about
implementing pledge on the application level, SElinux requires passionate
sysadmins who actually care about using it, and about their co-workers using
it.

------
lobster_johnson
Previous discussion:
[https://news.ycombinator.com/item?id=10306611](https://news.ycombinator.com/item?id=10306611)

~~~
LukeShu
That's a very similar presentation, but this one includes some new details.
(Notably that it was renamed from "tame" to "pledge")

------
JoachimS
Not to claim that they are remotely the same, but this reminds me of Microsoft
Drawbridge.

Drawbridge classifies syscalls into groups and the syscalls an application is
allowed to use is registered. When the application is executed a runtime
gateway verifies that the application only uses the syscalls that was
registered. Drawbridge does more things (generates a library that maps the
800+ syscalls to the group equivalent one etc.). But there are similar ideas.

I thought Drawbridge was neat, but seems not to have moved much beyond MSR.

[http://research.microsoft.com/en-
us/projects/drawbridge/](http://research.microsoft.com/en-
us/projects/drawbridge/)

~~~
joveian
Interesting... Drawbridge sounds like rump kernels (which can be used in
userland processes as well as in VMs), where everything the application does
is turned into a small number of hypercalls (12ish IIRC). It seems like there
are RISC and CISC forms of higher security system call interfaces (e.g. pledge
needing sendsyslog(2) and SOCK_DNS). It is good to see both approaches getting
more use :). I hope pledge is adopted widely as it seems like a good approach
to easily get significant improvement (particularly when exec is not needed,
since restrictions are not inherited).

A link to the pledge man page since I haven't seen it mentioned yet:
[http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-
current/man2/...](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-
current/man2/pledge.2)

------
elchief
De Raadt sounds like a pleasant, wise human in his slides (let's not talk
about the mailing list).

I'm really looking forward to 5.9 if it includes pledge as well as vmm (native
hypervisor)

~~~
MBCook
Really? Tame/pledge seems like a good interface but the dig at Linus seemed
unnecessary, the masturbating monkey was totally uncalled for, and the coil of
poop juvenile.

Seriously lowered my view of the presentation.

~~~
detaro
Linus was the one calling the OpenBSD developers "m...... monkeys" (apparently
that word triggers the HN spamfilter, I vouched your comment), so I think the
OpenBSD guys are allowed to be "a bit miffed".

~~~
1781
well, this is a good example of the dangers of dropping to the lower level of
the opposition; taken out of context, the images in the slides have a counter-
productive effect on the presentation. You just always have to hold higher
standards, or get dragged into the mud.

~~~
tachion
This only happens when we're (and I do mean all of us, not only a general IT
crowd, but people, society as a whole) are too serious about ourselves, up to
the level of butt-tight about it. I can't get insulted by the shiny pile, I
cant get insulted by the monkey. In best case I'll think its mildly funny and
adds some... shine to the presentation, at worst I'll think its simply a lack
of good taste and move on with it.

~~~
MBCook
I'm not insulted, but I find them tasteless and distracting. Other humor would
probably fit better.

------
viraptor
Unfortunately just the new api is not enough. Developers still need to
actually use it. When I researched seccomp and got really excited about it, I
submitted a patch to memcached to enable a restrictive policy. The patch/pr is
still there, months later. If the project doesn't care, no amazing tool is
going to help us :-(

~~~
quanticle
Theo understand that, and that's why he's pushing to get the core OpenBSD
userspace tools to use pledge. And hopefully, like many other security
innovations, patches will spread from OpenBSD to other operating systems.

------
biot
In relation to mitigations, what are the "Loudmouth Linus" and "recent article
in Washington Post" references about?

~~~
bronson
[http://www.washingtonpost.com/sf/business/2015/11/05/net-
of-...](http://www.washingtonpost.com/sf/business/2015/11/05/net-of-
insecurity-the-kernel-of-the-argument/)

Linus, in one of his less bright moments, called the OpenBSD team a bunch of
masturbating monkeys [1]. Unfortunately, the Linux kernel's conspicuous lack
of attack mitigation measures (compared to Win/Mac/OpenBSD/etc) does make one
wonder who has been masturbating over the past few years.

[1]
[http://article.gmane.org/gmane.linux.kernel/706950](http://article.gmane.org/gmane.linux.kernel/706950)
(from the article)

(to be clear: I like and use Linux a lot... but Linus's disregard for security
is becoming a liability)

------
sarciszewski
I would love to see all the other operating systems adopt pledge(), but as is
often the case with OpenBSD's security mitigations, it will be years before we
see it happen (if at all).

~~~
pkaye
Why do you feel this way when even OpenBSD hasn't fully worked out all the
details (see the slides) and proven it will work well in practice.

~~~
sarciszewski
Because I think whitelisting the syscalls at init and only being able to drop
syscalls is a great idea.

------
malkia
I'm wondering how does this work in a world of plugins? (for example
Windows/oSX world, where programs like Autodesk 3DSMax/Maya, Adobe Photoshop,
etc. use plugins)?

Or applications that embed many utils into one?

~~~
badalex
It's not much different than seccomp/systrace/apparmor/grsec rbac/selinux in
that regard. It's per process. So sure, if the plugin forks it could pledge().
Much the same way the plugin could seccomp once forked. Otherwise the plugins
rules would be applied to the application.

All the same, even if the app used it with most syscalls enabled, it would
reduce the attack surface.

~~~
viraptor
Actually seccomp is per-thread. Small difference, but it does make some
lighter use possible in case of plugins.

------
dllthomas
I toyed with a similar idea for Linux a while back. Posted about it but got
busy and never followed up:
[https://lkml.org/lkml/2009/6/24/8](https://lkml.org/lkml/2009/6/24/8) I'd
forgotten about it entirely...

------
andrewchambers
Is this a rename of the tame() function that was posted earlier?

~~~
sirsar
Yes.

> _formerly known as tame()_

[http://www.openbsd.org/papers/hackfest2015-pledge/mgp00002.h...](http://www.openbsd.org/papers/hackfest2015-pledge/mgp00002.html)

~~~
andrewchambers
Oh my mistake, I skipped the "About Openbsd" slide because I already knew what
openbsd was :).

------
Arnt
Why is pledge() int rather than void? All the examples exit() in one way or
another, so why doesn't pledge() do that for them?

~~~
glass-
The examples are just examples, the uses in the tree are different. For
example, ksh doesn't exit if pledge fails, it just prints an error about why
it failed and keeps running (imagine how fun it would be the shell did just
keep terminating). Other programs use their own logging to report the error,
for example httpd logs the error the same way it logs all other fatal errors
before it exits.

~~~
bobdole1951
Heh, that was just changed today:

[https://marc.info/?l=openbsd-
cvs&m=144721043826274&w=2](https://marc.info/?l=openbsd-
cvs&m=144721043826274&w=2)

------
dllthomas
I wonder if there is any reason to use pledge() to move between program stages
rather than exec(). It would require arranging your executables a little
differently, but should be tractable and probably backwards compatible, and
the increased resolution would be exposed to existing MAC frameworks.

------
caf
Dismissing SELinux as _" optional security is irrelevant"_ seems pretty silly,
since just as one can choose not to use SELinux, they can equally choose not
to use OpenBSD. Either way it comes down to the choice of the administrator.

OK, people clearly disagree - but I'm still not seeing it, so can someone
please explain what's more optional about SELinux than OpenBSD? I mean, I'm
not trying to make some kind of a gratuitous dig here, I'm trying to make a
serious contribution to the discussion.

They're different kinds of mitigation mechanisms anyway, that could easily
work together. plege() (and seccomp-bpf) are mitigations intended to be
applied by the application author, of the _" I know my IRC client should never
call ptrace()"_ sort. SELinux is a mitigation intended to be applied by the
system administrator, of the _" I know my ETL loader job should only need to
read files labelled with loader-input label, write to the directory labelled
with the loader-temp label, and connect to the syslog and database sockets"_
sort.

~~~
throwaway2048
OpenBSD develoers have no control over other operating systems, but they can
ensure running OpenBSD means mandatory pledge. It is a given that statements
about OpenBSD tech _apply only when running openbsd_ .

You are invoking some pretty ridiclous semantics to dispute "optional".

------
ansible
SELinux is on by default now with Android. So that's good. I don't know when
it will be on by default for the majority of desktop and server users though.

------
fidget
Probably worth noting that seccomp bpf programs are pretty far from turing
complete.

Though they are a bit complex.

------
dantetwc
OMG! Comic Sans again.

~~~
illumen
These security hipsters think it makes them cool.

~~~
TazeTSchnitzel
No, they just enjoy upsetting people who don't like the font :)

------
nickysielicki
Linus is gonna need some ice for that burn on page 3! Jeez!

