<commit_before>---
layout: post
title: 'Objects as Secure Capabilities'
date: 2015-11-10 16:03:00.000000000 -08:00
categories: []
tags: []
status: publish
type: post
published: true
author:
  display_name: joeduffy
  first_name: Joe
  last_name: Duffy
  email: <EMAIL>
---
[Last time](http://joeduffyblog.com/2015/11/03/a-tale-of-three-safeties/), we
saw how Midori built on a foundation of type, memory, and concurrency safety.
This time, we will see how this enabled some novel approaches to security.
Namely, it let our system eliminate [ambient authority and access control](
https://en.wikipedia.org/wiki/Ambient_authority) in favor of [capabilities](
https://en.wikipedia.org/wiki/Capability-based_security) woven into the fabric
of the system and its code.  As with many of our other principles, the
guarantees were delivered "by-construction" via the programming language and its
type system.

# Capabilities

First and foremost: what the heck are capabilities?

In the security systems most of us know and love, i.e. UNIX and Windows,
permission to do something is granted based on identity, typically in the form
of users and groups.  Certain protected objects like files and system calls have
access controls attached to them that restrict which users and groups can use
them.  At runtime, the OS checks that requested operation is permitted based on
these access controls, using ambient identity like what user is running the
current process.

To illustrate this concept, consider a simple C call to the `open` API:

	void MyProgram() {
		int file = open("filename", O_RDONLY, 0);
		// Interact with `file`...
	}

Internally, this call is going to look at the identity of the current process,
the access control tables for the given file object, and permit or reject the
call accordingly.  There are various mechanisms for impersonating users, like
`su` and `setuid` on UNIX and `ImpersonateLoggedOnUser` on Windows.  But the
primary point here is that `open` just "knew" how to inspect some global state
to understand the security implications of the action being asked of it.
Another interesting aspect of this is that the `O_RDONLY` flag is passed, asking
for readonly access, which factors into the authorization process too.

Well, what's wrong with this?

It's imprecise.  It relies on ambient state that is invisible to the program.
You can't easily audit to see the security implications of the operation.  You
just need to know how `open` works.  And thanks to its imprecision, it's easy to
get wrong, and going here wrong means security vulnerabilities.  Specifically,
it's easy to trick a program into doing something on behalf of a user that it
was never intended to do.  This is called the ["confused deputy problem"](
http://c2.com/cgi/wiki?ConfusedDeputyProblem).  All you need to do is trick the
shell or program into impersonating a superuser, and you're home free.

Capability-based security, on the other hand, isn't reliant on global authority
in this same manner.  It uses so-called "unforgeable tokens" to represent
capabilities to perform operations.  No matter how the decision is made, if the
software isn't meant to perform some operation, it simply never receives the
token necessary to do said operation.  Since tokens are unforgeable, the program
cannot even attempt the operation.  In a system like Midori's, type safety meant
that not only could the program not perform the operation, it would often be
caught at compile-time.

The hypothetical `open` API from earlier, as you may have guessed, would look
very different:

	void MyProgram(File file) {
		// Interact with `file`...
	}

I've just passed the buck.  *Someone else* has to show up with a File object.
How do they get one?  That's up to them.  But if they *do* show up with one,
they must have been authorized to get it, because object references in a type
safe system are unforgeable.  The matter of policy and authorization are now
pushed to the source.

I'm over-simplifying a little bit, since most of the interesting questions just
evaporated from the conversation.  Let's keep digging deeper.

How does anyone actually produce a File object?  The code above neither knows
nor cares whether where it came from.  All it knows is it is given an object
with a File-like API.  It might have been `new`'d up.  More likely, it was
obtained by consulting a separate entity, like a Filesystem or a Directory:

	Filesystem fs = ...;
	Directory dir = ... something(fs) ...;
	File file = ... something(dir) ...;
	MyProgram(file);

You might be getting really angry at me now.  Where did `fs` come from?  How did
I get a Directory from `fs`, and how did I get a File from `dir`?  One could
reasonably claim I've just squished all the interesting topics around, and
answered very few.

The reality is that those are all the interesting questions you encounter now
when you try to design a filesystem using capabilities.  You probably don't want
to permit free enumeration of the entire filesystem hierarchy, because if you
get access to a Filesystem object -- or the system's root Directory -- you can
access everything, transitively.  That's the sort of thinking you do when you
begin dealing with capabilities.  You think hard about information encapsulation
and exposure, because all you've got are objects to secure your system.
Probably, you'll have a way that a program requests access to some state
somewhere on the Filesystem, declaratively, and then the "capability oracle"
decides whether to give it to you.  This is the role our application model
played.  From that point onwards it's just objects.  The key is that nowhere in
the entire system will you find the classical kind of ambient authority, and so
none of these abstractions can "cheat" in their construction.

A classic paper, [Protection](
http://research.microsoft.com/en-us/um/people/blampson/08-Protection/Acrobat.pdf),
by <NAME> clearly articulates some of the key underlying principles.  In
a sense, each object in our system is its own "protection domain."  I also love
[Capability Myths Demolished](http://srl.cs.jhu.edu/pubs/SRL2003-02.pdf)'s way
of comparing and contrasting capabilities with classical security models, if you
want more details (or incorrectly speculate that they might be isomorphic).

Midori was by no means the first to build an operating systems with object
capabilities at its core.  In fact, we drew significant inspiration from
[KeyKOS](http://www.cis.upenn.edu/~KeyKOS/NanoKernel/NanoKernel.html) and its
successors [EROS](https://en.wikipedia.org/wiki/EROS_(microkernel)) and
[Coyotos](http://www.coyotos.org/docs/misc/eros-comparison.html).  These
systems, like Midori, leveraged object-orientation to deliver capabilities.  We<commit_msg>Even more wordsmithing<commit_after>---
layout: post
title: 'Objects as Secure Capabilities'
date: 2015-11-10 16:03:00.000000000 -08:00
categories: []
tags: []
status: publish
type: post
published: true
author:
  display_name: joeduffy
  first_name: Joe
  last_name: Duffy
  email: <EMAIL>
---
[Last time](http://joeduffyblog.com/2015/11/03/a-tale-of-three-safeties/), we
saw how Midori built on a foundation of type, memory, and concurrency safety.
This time, we will see how this enabled some novel approaches to security.
Namely, it let our system eliminate [ambient authority and access control](
https://en.wikipedia.org/wiki/Ambient_authority) in favor of [capabilities](
https://en.wikipedia.org/wiki/Capability-based_security) woven into the fabric
of the system and its code.  As with many of our other principles, the
guarantees were delivered "by-construction" via the programming language and its
type system.

# Capabilities

First and foremost: what the heck are capabilities?

In the security systems most of us know and love, i.e. UNIX and Windows,
permission to do something is granted based on identity, typically in the form
of users and groups.  Certain protected objects like files and system calls have
access controls attached to them that restrict which users and groups can use
them.  At runtime, the OS checks that the requested operation is permitted based
on these access controls, using ambient identity like what user is running the
current process.

To illustrate this concept, consider a simple C call to the `open` API:

	void MyProgram() {
		int file = open("filename", O_RDONLY, 0);
		// Interact with `file`...
	}

Internally, this call is going to look at the identity of the current process,
the access control tables for the given file object, and permit or reject the
call accordingly.  There are various mechanisms for impersonating users, like
`su` and `setuid` on UNIX and `ImpersonateLoggedOnUser` on Windows.  But the
primary point here is that `open` just "knew" how to inspect some global state
to understand the security implications of the action being asked of it.
Another interesting aspect of this is that the `O_RDONLY` flag is passed, asking
for readonly access, which factors into the authorization process too.

Well, what's wrong with this?

It's imprecise.  It relies on ambient state that is invisible to the program.
You can't easily audit to see the security implications of the operation.  You
just need to know how `open` works.  And thanks to its imprecision, it's easy to
get wrong, and going here wrong means security vulnerabilities.  Specifically,
it's easy to trick a program into doing something on behalf of a user that it
was never intended to do.  This is called the ["confused deputy problem"](
http://c2.com/cgi/wiki?ConfusedDeputyProblem).  All you need to do is trick the
shell or program into impersonating a superuser, and you're home free.

[Capability-based security](https://en.wikipedia.org/wiki/Capability-based_security),
on the other hand, isn't reliant on global authority in this same way.  It uses
so-called "unforgeable tokens" to represent the ability to perform privileged
operations.  No matter how the decision gets made -- there is an entirely complex
topic of policy management and granting authority that gets into social and human
behaviors -- if the software isn't meant to perform some operation, it simply
never receives the token necessary to do said operation.  And because tokens are
unforgeable, the program can't even attempt the operation.  In a system like
Midori's, type safety meant that not only could the program not perform the
operation, it would often be caught at compile-time.

Insecure operations rejected at compile-time, how cool is that!

The hypothetical `open` API from earlier, as you may have guessed, would look
very different:

	void MyProgram(File file) {
		// Interact with `file`...
	}

OK, clearly we're not in Kansas anymore.  This is *extremely* different.  And
I've just passed the buck.  *Someone else* has to show up with a File object?
How do they get one?

The trite answer is, who cares, that's up to the caller.  But if they *do* show
up with one, they must have been authorized to get it, because object references
in a type safe system are unforgeable.  The matter of policy and authorization
are now pushed to the source where, arguably, they belong.

I'm over-simplifying a little bit, since this answer likely raised more questions
than it actually answered.  Let's keep digging deeper.

So, again, let's ask the question: how does one get their hands on a File object?

The code above neither knows nor cares whether where it came from.  All it knows
is it is given an object with a File-like API.  It might have been `new`'d up by
the caller.  More likely, it was obtained by consulting a separate entity, like
a Filesystem or a Directory, both of which are also capability objects:

	Filesystem fs = ...;
	Directory dir = ... something(fs) ...;
	File file = ... something(dir) ...;
	MyProgram(file);

You might be getting really angry at me now.  Where did `fs` come from?  How did
I get a Directory from `fs`, and how did I get a File from `dir`?  I've just
squished all the interesting topics around, like a water balloon, and answered
nothing at all!

The reality is that those are all the interesting questions you encounter now
when you try to design a filesystem using capabilities.  You probably don't want
to permit free enumeration of the entire filesystem hierarchy, because if you
get access to a Filesystem object -- or the system's root Directory -- you can
access everything, transitively.  That's the sort of thinking you do when you
begin dealing with capabilities.  You think hard about information encapsulation
and exposure, because all you've got are objects to secure your system.
Probably, you'll have a way that a program requests access to some state
somewhere on the Filesystem, declaratively, and then the "capability oracle"
decides whether to give it to you.  This is the role our application model
played.  From that point onwards it's just objects.  The key is that nowhere in
the entire system will you find the classical kind of ambient authority, and so
none of these abstractions can "cheat" in their construction.

A classic paper, [Protection](
http://research.microsoft.com/en-us/um/people/blampson/08-Protection/Acrobat.pdf),
by <NAME> clearly articulates some of the key underlying principles, like
unforgeable tokens.  In a sense, each object in our system is its own "protection
domain."  I also love [Capability Myths Demolished](
http://srl.cs.jhu.edu/pubs/SRL2003-02.pdf)'s way of comparing and contrasting
capabilities with classical security models, if you want more details (or
incorrectly speculate that they might be isomorphic).

Midori was by no means the first to build an operating systems with object
capabilities at its core.  In fact, we drew significant inspiration from
[KeyKOS](http://www.cis.upenn.edu/~KeyKOS/NanoKernel/NanoKernel.html) and its
successors [EROS](https://en.wikipedia.org/wiki/EROS_(microkernel)) and
[Coyotos](http://www.coyotos.org/docs/misc/eros-comparison.html).  These
systems, like Midori, leveraged object-orientation to deliver capabilities.  We
{'fraction_non_alphanumeric': 0.0617644961129734, 'fraction_numerical': 0.006418943014050353, 'mean_word_length': 4.38479262672811, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 7, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4037528', 'n_tokens_mistral': 3869, 'n_tokens_neox': 3635, 'n_words': 2040}