L4 microkernels: The lessons from 20 years of research and deployment
ts.data61.csiro.au
ts.data61.csiro.au
L4 got rid of "long message passing", in favor of shared memory and interrupt-like IPC. This is great for the kernel - no copying delays and no buffering problems. But it means that communicating processes have to share some memory pages and cooperate properly. If the shared memory page is something like a chain of linked buffers, one side may be able to screw up the other side. If that's how you talk to the file system, it may be possible to attack the file system process that way. This won't crash the kernel.
Because L4's API is so limited, it's used mostly as a VM, with the usual bloated Linux kernel on top. QNX has only a few more kernel features than modern L4, but it can implement the POSIX API with just support in the C library. When you call "write()" from C/C++ in QNX, the C library makes a MsgSend request which is directed to a file system service, device service, or network service. The code for this is tiny. When you call "write()" from C/C++ on L4, you're usually just making a Linux system call to an ordinary big Linux in a VM. Eventually that Linux talks to other processes which do the physical disk I/O. The problem is that the giant Linux kernel is still there, just a bit more isolated from the hardware. The total amount of code that can break has not been reduced significantly.
They recently added support for running on seL4 too: https://sel4.systems/pipermail/devel/2016-August/000967.html
My intuition, not carefully checked:
I'd rather be using QNX than Linux on L4, but I'd rather be using just L4 than QNX.
My favorite table:
Kernel Source Lines of Code (SLOC)
OKL4 13.8k
QNX Neutrino v6.3.2 23k
Linux Kernel 2.6.0 5.2M
Windows XP Kernel size unknown but totals at approx 40M
Windows Vista Kernel size unknown but totals at approx 50M
Modern microkernels are so small that they can be thoroughly debugged, or formally verified.[1] http://www.gelato.unsw.edu.au/IA64wiki/JamieLennox/QNXvL4?ac...
> https://en.wikipedia.org/w/index.php?title=QNX&oldid=7308275...
"In September 2007, QNX Software Systems announced the availability of some of its source code. [http://www.qnx.com/news/pr_2471_1.html]
On April 9, 2010, Research In Motion announced they would acquire QNX Software Systems from Harman International Industries. On the same day, QNX source code access was restricted from the public and hobbyists."
All I have found is a really old version that doesn't seem to have much in common with the current one.
https://github.com/tomga/genode/commit/c8a64b5c3465cde1723b2...
OKL4 Release 2.1
================
Date: 15 April 2008http://ts.data61.csiro.au/publications/papers/Heiser_10:iids...
Just one simple example: run "sample <process>" (where <process> is any Cocoa application) on OS X. Pretty much every thread will have an event loop powered by CFRunLoop, and they'll all be stuck in mach_msg_trap waiting for an event to occur.
Also, pretty much any sort of semi-complicated IPC on OS X is done over Mach IPC (e.g. passing a large bitmap copy-on-write from one process to another). Take a look at the ipc directory in the Chromium source, for example.
Edit: oh, and you can still run seL4 as hypervisor and run Linux on top of it to get the usual Embedded Linux stack where your CPU has enough juice. And still keep the critical systems safe behind seL4's capability system. Best of both worlds? Dunno, hopefully seL4 will be there someday in production quality.
- No longer need the verification of application make assumptions about the semantics of the operating system. Instead, concrete and verified semantics are available. This makes application specification and verification easier, and safer. Fortunately, verification is cumulative
- The seL4 project has driven the state-of-the-art of verification tool forwards by a considerable degree.
- The seL4 project has lead the thinking about proof engineering [1], the emerging field that that is to verification what software engineering is to programming, addressing the question how to develop, maintain and evolve large-scale proofs.
- The existence of something like seL4 also puts pressure on CPU manufactures to provide usable formal specifications to their customers, so that we can verify against rigorous CPU specs. CPU manufacturers have been loath to do this (for various reasons).
The full verification of seL4 came a lot earlier (by about a decade) than I thought possible.
[1] G. Klein, Proof Engineering Considered Essential.
Really I think it depends on what you're doing. If the work you're doing is fundamentally kernel work --- if it's all about interacting with the security boundaries of the hardware (not just "interacting with hardware", like getting the bits from an RF codec, but manipulating hardware shared by attackers, like the iPhone SEP) then L4 is a pretty huge security win.
Otherwise: the problem you have isn't your OS, but the programming language you're using to build with.
1. Device driver isolation. Wacky drivers can take down the system. Better to take down and restart the driver. QNX was first I know of that did this with excellent reliability benefits. Many of them do now in RTOS space. MINIX 3 takes it to desktops and servers.
2. Monitors like in Copilot system or for recovery-oriented computing that expects input to crash or subvert main process. So, outside process is necessary for detection of anomalous behavior and recovery. Periodic restarts are another trick used in that field to clear out subtle errors that build up over time or persistent malware. Best to be in different address spaces.
3. Dedicated process, as in Nizza and Turaya, for containing application secrets where external processes can call to have random numbers generated, signatures performed, etc but not actually access the internals.
4. Same thing for logging purposes where interface between main app and logging component is write-only. Prevents accidental or malicious elimination of audit trail. I did that myself many times. Shapiro et al did it for repo security.
5. Finally, separation kernels like INTEGRITY-178B can ensure predictability of certain operations and statically enforce a scheduling policy. That's important in real-time systems where a number of tasks are running where one can screw with the other. So, they use things like ARINC schedulers with fixed-sized partitions operating in fixed intervals. Watchdog timers are also popular here. Also is a strategy for eliminating covert, timing channels at partition level for select few that need that.
What you typically get is a neat subdivision of all the HAL bits, but everyone stops once they're plugging in applications. This is partly because there's normally a large amount of shared/legacy code which needs importing, and partly because people don't recognize the benefits of partitioning an app.
It's not all bad - at least you can be reasonably confident that one compromised app, or part of the HAL, can't be trivially used to compromise the rest of the system. But, as you say elsewhere here, if there's just one thing you're doing, then all that effort didn't really improve things.
(I've done some L4 work so you don't need to spend a lot of time explaining.)
General purpose OSs like iOS? No question: L4 is a major win. But that's not what the discussion here is really about.
Consider, for instance, that it is possible to separate TCP/IP or wireless protocol stacks from authentication code so that, for instance, a packet fragmentation bug can't be exploited to influence authentication level decisions. This is classical defense in depth strategy, but enforced through both runtime and formal methods.
I guess it all depends on which meaning of IoT and embedded you are using.
The beginning availability of verified kernels and compilers makes it much more worthwhile to invest in formal approaches for application level vulnerabilities.
Is it a full verification yet? I am by no means an expert, but IIRC, they were still using a simplified model MMU in their proofs.
Second, in IoT devices, sandboxing is a lot less interesting, because there aren't that many use cases for sandboxed sensor inputs (you're not RFing or button-pushing whole PDF documents).
I like L4! A lot! But I would be very wary of an IoT device claiming to have inherited security from it.
The theorems are somewhat technical, but your intuition is correct.
Skimming that, I got that (a) PHigh -> PLow via overt channels will be degraded, and that (b) seL4 reduces the attack surface to "covert channels" only which seem to be confined to H/W "platform" concerns.
You could do the equivalent of solving world hunger and world peace, but unless you also give everyone in the world a free puppy, you're going to get bad reviews complaining about the lack of puppies. And there's always someone who wanted a kitten instead...
But the whole point is that usually in embedded systems, there is no separation between "application" and "kernel", at least on the low-end of CPU power scale. To be able to isolate application level problems from kernel would already be a huge boon.
As a highly publicized anecdote, the Jeep hack of Miller and Valaseck was done by attacking through wireless, and replacing the CAN driver code to suit their needs. Not possible with proper isolation between critical system drivers and application layer.
It can also happen when using unsafe code with the Ada, Java, Pascal and Basic variants available for such devices, but the probability is lower.
Of course, the whole thing was broken anyhow as everything was running root.
But in almost everything else, I agree. I don't care if you have ring-0 on my Nest camera, because I'm more worried about network-level attacks or an attacker being able to read from the camera which (I'm guessing) is available via user space.
1: https://pdfs.semanticscholar.org/bc9c/491e215d4abad1be7de944...
The isolation helps reducing the attack surface.
There is only one thing that will fix the problem, and that is when corporations get hit in the wallet for having security flaws, see for example: https://medium.com/@xParXnoiAx/irresponsible-disclosure-52d0...
I'd understand if the autopilot's AI or whatever wasn't perfect due to the complexity of the job or the graphics stack occasionally had artifacts in it. The systems not having basic security measure that budget startups pull off indicates it's not that such a baseline was too difficult: they just don't give a shit.
https://os.inf.tu-dresden.de/papers_ps/nizza.pdf
The first to get certified to high assurance under recent models and delivered in products was INTEGRITY-178B. Like Nizza, they implemented desktops that virtualized the machine with Windows/Linux partitions side-by-side with native apps directly on separation kernel. Runtimes for Ada and Java subsets let you write critical components without common errors from C. Special middleware applies security policies to interactions between components.
http://www.ghs.com/products/safety_critical/integrity-do-178...
A recent product that's more accessible is the GenodeOS architecture that builds hierarchical, desktop system on top of components like seL4, NOVA, and Nitpicker GUI. They're dual-licensed with open-source available. Work in progress.
It should be noted that seL4 itself is aiming for embedded. Many of the top teams are also focusing on language and spec-level models for verification of holistic properties. The isolation approach isn't enough for the level of correctness they're aiming for. Anyone interested in such work should check out Galois's project or CertiKOS.
It seems more manageable to verify a few KB of assembly or C
https://ts.data61.csiro.au/projects/TS/cogent.pml
Note: See "Cogent: Verifying high-assurance file system..."
They leverage the same tools used for seL4 verification. Also worth noting that Myreen et al's toolkit basically converts HOL specifications to machine code without need for an external compiler. The "C" that was compiled was an embedding of it in HOL called Simpl which the aforementioned process verifies and converts to verified code. This is called translation validation. That's my non-specialist understanding of what the papers said. COGENT builds on this process to convert functional language and easier specs into that form which gets trans-validated into machine code. With less effort. :)
Note: Myreen et al are doing both verifications of HOL itself and HOL to hardware translation next. These further reduce the TCB of provers and hardware respectively to almost nothing but the specs.
Look for the part where they identify their responsibility for the fact that after 20 years and thousands of engineer hours at their disposal they still don't have a microkerenel based operating system worth a pinch of anything. I'm not trolling, I'd love it if that statement were false.
"For a successful technology, reality must take precedence over public relations, for Nature cannot be fooled." --Richard Feynman
I don't have personal knowledge of these environments, so I wouldn't know if I were wrong about this.