I'll add a link to the blog post when it's live.
See the post at: http://unikernel.org/blog/2015/contain-your-unikernels/
I suppose the difference here is that pledges use a single kernel but restrict kernel interfaces for each process while the unikernel approach creates a kernel subset for each VM (and thus each process, for VMs dedicated to a single process).
Can anyone knowledgeable comment about the advantages or disadvantages of each? I'm guessing unikernals will be more portable (only OpenBSD is doing pledges to my knowledge) and more popular with the containerization movement. Can pledges accomplish the same objective with better use of system resources?
Edit: clarity about portability point
 one of the reasons for pledge(2) was the realisation/understanding that many applications have an initial setup phase followed by a "stable state", where the stable state needs significantly less services than the setup e.g. setup might require reading config files but the steady state doesn't and just listens on a socket, so you can call pledge(2) multiple times and further reduce the application's abilities (attempting to increase them will fail with EPERM)
Pledging is the most usable form of priv-dropping I've seen yet in any OS, since it was designed after looking at the "flow" of how a typical daemon interacts with the kernel, rather than a low-level syscall interface that the typical programmer would have no idea about. I've used many of the different privilege dropping interfaces in OpenBSD over the years, and to recall the journey:
- Separating out syslogd back in 2003 was a fun adventure in manual privsepping before it became mainstream; I think just sshd used in it base before that. This required building an automaton of how the privileged messages from syslog would work, and carefully coordinating the state machine and message passing around that. http://marc.info/?l=openbsd-cvs&m=105967566808306&w=2
At this point we had two processes, but the root process couldn't do fine-grained dropping of privileges and just had to be carefully audited by lots of people.
- systrace came along, which allowed policies to be built about which syscalls could be called. The policy language was limited, so I got really excited by the possibilities and wrote a DSL to make it easier to build systrace policies; http://anil.recoil.org/papers/sam03-secpol.pdf. In the end I gave up on using systrace since it was so brittle to unrelated changes in libc or dependent libraries changing the order of system calls and causing apps to break all the time.
- Pledge is almost the opposite of systrace. You provide a series of human-readable strings, and the OS takes care of mapping those to groups of syscalls. This makes so much more sense, since the person making the change can also update the pledge, and applications don't break! If you look at OpenBSD current, over half of the base daemons are now pledging. At no point are there insanely complex policies like SELinux, nor are there the race conditions of systrace. In fact, the most similar approach to this I've found is MacOS X entitlements, which also let the application specify what functionality it would like (as opposed to what syscalls it needs)
So, what's the relation to unikernels? Well, they are completely the opposite approach. Instead of starting with a wide kernel interface and then restricting it, unikernels start with a very narrow interface (the hypervisor) and build up higher level abstractions as they are demanded by the application.
This happens via a series of libraries, and so the programmer can choose at compile time how to weave in privilege levels and the use of hardware enforcement (such as processes).
I can see both pledge and unikernels converging in the future, specifically by a linker that would be aware of the pledges that a library needs, and mapping the appropriate hardware enforcement into the resulting unikernel. I'm not aware of anyone actually working on this, but get in touch with me if you are interested... (email@example.com)
You're forgetting that unikernels are a library OS and not tied to a particular hypervisor at all. MirageOS code can currently be compiled to target:
- the Xen hypervisor via MiniOS, with Mirage-supplied implementations of XenStore/device drivers/TCPIP
- bare metal and the KVM hypervisor via Rump Kernel
- UNIX binaries via tuntap (which work great with Linux containers).
And future backends -- the MirageOS frontend just needs to swap out and link in the right libraries for the desired platform. And even when Linux containers get a complete isolation story, if you build applications as unikernels you can also choose to isolate kernel components that will never be covered by the current Linux container architecture (such as the TCP/IP stack).
Edit: So as long as hardware virtualization is dominant in public clouds, a unikernel is a nice optimization for applications that only require a single process.
You can't just take the lines of code as a comparison. You have to look how much code is actually exposed to potential attackers.
The other unikernel projects (i.e. MirageOS and HaLVM), take a clean-slate approach which means application code also has to be in the same language (OCaml and Haskell, respectively). However, there's also ongoing work to make pieces of the different implementations play nicely together too (but it's early days).
That's a good argument but seems to be one for rump being the past's future (unikernel-ifying legacy applications) rather than for it being the future itself.
Being able to build your unikernel (micro)services using legacy things and then swapping out certain services for clean-slate versions seems like a much more palatable approach. This is why unikernels fit so well with the microservices approach — you only have to re-write things one piece at a time if you choose to.
That's kind of my point, in that worldview rump kernels are not really the future they're a transitional phase bridging the present and the future.
besides, think of all the future cool stuff you can more easily build on top of rump kernel (almost a year in the IRC channel and I still can't recall how I'm supposed to refer to...it) rather than being "stuck" with just Erlang on LINC or Haskell on HalVM etc.