Thoughts on an object-capability file store

As mentioned in the last few posts, I've been thinking a lot lately about the role of filesystems in a secure capability system.

One of the things that occurs to me is that a POSIX file system isn't going to be a suitable abstraction for persistent storage. I realised this while thinking about files and memory as presenting similar interfaces. Namely, in an object-capability system, memory is per-object and not necessarily per-application (like it is with the Unix process model). Files should be treated similarly, which means that there needs to be a mechanism where specific sets of objects can dynamically be granted or revoked access to a file entry.

In order to make useful decisions about the security of a given file object, access control needs to rest with the creator of the object. However, in the POSIX model, the owner of a file doesn't have any control over the membership of the "group" or "other" sets (assuming a system where the user is not the superuser). While the user might be able to select the group, they still can't create a group or modify its membership. A filestore supporting capabilities should be able to make this distinction.

This does mean my original idea of using a separate ext2 image for each unikernel might not be the best idea.

Here's one idea I had: use filenames (which I think might be defined similarly to <owner>:<namespace>:<label>) as a symbolic link to a SHA-256 hash of a file entry in a CAS1 system. Each file entry would contain metadata for time of creation and last access, a UUID referring to the owner, a set of capabilities, a flag to indicate whether the file is an archive entry (i.e., it shouldn't be garbage collected and a backup system may treat it differently), and a UUID pointing to the parent entry, as applicable.

The CAS aspect means that the only two capabilities that I think this needs are Read and ReadParent. The former grants read access only to this entry, whereas the previous grants read access to the parent node. (I'm not sure this is actually right; the right answer is probably to grant a capability for both this entry and the parent.) To write to the file means creating a new entry, which will be owned by its creator.

I have a long-running project to build a CAS-over-HTTP in Haskell as a toy project. It might serve as a useful testbed for some of these ideas. I imagine the implementation would proceed in the following steps:

  1. Basic file and entry implementation (no authentication, ownership by label only) to model the core data structures and prototype the interface.
  2. First authentication phase: owner auth, no capabilities.
  3. Start adding support for capabilities. What do they look like? Can the CAS be integrated into an external capability system (e.g. what if it's running on top of W7)?

1. Content-addressable storage, in which content is referenced by the digest of its contents, rather than by a name.


Tags: , ,