Plash history
I started Plash in October/November 2004, having finished writing my Masters thesis at Johns Hopkins University in Baltimore. It was a few weeks before I was due to leave Baltimore and return to the UK.
Plash came out of two ideas I had been exploring before:
- Virtualising filesystem access by changing glibc
- A Bash-like POLA shell
Filesystem virtualisation was something I had explored in the summer of 2001 while an undergraduate. I rebuilt glibc to insert my own code to replace functions such as open(). I started on creating a capability-based message-passing system for communicating between libc and a server process, allowing file descriptors to be sent in messages. I implemented a comms system with a server process written in OCaml -- sendmsg() and recvmsg() had to be wrapped using C extensions but the rest was pure OCaml -- while client code, to be linked into glibc, was written in C. The inspiration for this system was GNU Hurd: the motivation was more about allowing interesting filesystem abstractions to be written purely in user space than about providing security.
The POLA shell came out of an idea I had, also in the summer of 2001, for making C programs memory-safe, which involved tagging integer pointers with capabilities for memory blocks. I implemented the memory-safety scheme as part of my undergraduate third year project in 2001 and 2002. A related idea was to make programs treat filenames as capabilities by attaching capabilities to filename strings. I sketched out a scheme for implementing this with C, using a big hash table mapping string addresses to capabilities, with compiler support for propagating the tagged capabilities -- which I never implemented. But for this to work, the filename strings had to get tagged in the first place. My answer was that there would be a security-aware shell which would distinguish filename arguments to commands from other string arguments. I started to sketch out a syntax (an overly-complicated one) for the shell.
The immediate spur for working on Plash was a talk by Mark Miller to the programming languages lab at JHU (according to the lab seminar page, it was on 29th September). I think I had heard Mark do similar talks before, but this one set me thinking about why there was still no prototype for a POLA system using OS-based security on Unix. I started piecing together a system in my head. Afterwards I wrote down notes.
When I started it, Plash did not have a name, but I had to pick a name to release it under. The name referred to POLA and stood for the "principle of least authority shell". I released it in December 2004 (see the e-mail), soon after Alan Karp's post announcing Polaris, which does a similar thing under Windows. I wrote a few notes about how I had built Plash's version of glibc, but there was at the time no automatic build process.
What I did wrong before Plash
I made a number of mistakes in my first attempt at doing filesystem virtualisation.
- I tried to make the message system too high level. I wanted each message to be a "term tree" -- an abstract data type supporting integers, strings, lists, tuples, object references and file descriptors, based on term trees in Mozart/Oz. In order to find out what references and file descriptors were being passed in a message, you had to decode the tree, which was encoded in a text format. This was a pain to deal with in C. I should have focused on getting something working end-to-end, not making it abstract. Plash did this better: initially, messages were just an array of bytes and an array of FDs, with the initial 4 bytes used as a message/method name. Later, this was extended to a proper object-capability protocol, allowing multiple objects to be exported across a connection, and allowing object references to be passed in methods.
I got too hung up on how to do a module system. An earlier project I had been writing in Scheme in 2000 had reached the point where it needed a module system, something which standard Scheme does not provide. I investigated the various module systems available for Scheme and liked the PLT Units system. I wanted my custom glibc to get linked together using a Units-like module system. I wrote OCaml code that would generate objcopy invocations for linking up a symbol in one object file to a possibly-differently-named symbol in another object file. I tried to divide glibc into smaller components with understandable dependencies, and to do that I tried to generate dependency graphs of the object files' dependencies. The graphs were way too big and complicated: there is a tendency for one important part of glibc to depend on all the other important parts. Most of this effort was unnecessary. For Plash, I wrote out the objcopy invocations by hand (they simply hid or renamed a few symbols) and just used the conventional pool-based one-big-namespace system for linking object files. It wasn't necessary to understand the dependencies in the rest of glibc.
- Language choice: I began to doubt whether I should be writing the client code in C. Though I had written a decent amount of C before, recently I had been using high-level languages and had got more used to having garbage collection and memory safety. However, there was no other language other than C with implementations suitable for using in glibc. I contemplated writing a compiler for this task. That was an unnecessary diversion. For Plash, I just accepted that the code linked into glibc should be written in C. I made sure that I didn't make the code more abstract than necessary so that the C code would be simple.
- Language choice 2: Writing the server code in OCaml was probably a mistake. OCaml's strict static type system tended to get in the way when dealing with messages from the comms system which are inherently dynamically-typed. The bigger problem, though, was that code had to be written twice: the comms system had to be implemented in both C and OCaml. For Plash, everything was written in C, including the shell (with the exception of a parser generator, written in OCaml). This was simpler in the sense that it removed the need for deciding what language to implement each part in. There were no artificial boundaries to code re-use. Now that Plash is older, I am writing more of it in Python. Doing this at the start would probably have been a hindrance, though, because it was less clear what the overall structure of the system was going to be.
