Research work by Merjen Kakajanova student of International University for the Humanities and Development. Instructor Nurmyrat Allayarov.
Monoliths, microkernels and a thirty-year fight over a deceptively simple question: what actually belongs inside the kernel?
On 29 January 1992, Andrew Tanenbaum, a professor in Amsterdam and the author of the MINIX teaching operating system, posted a message to a Usenet newsgroup under the subject line “LINUX is obsolete.” The target was a hobby kernel that a Finnish student named Linus Torvalds had released a few months earlier. Tanenbaum’s complaint was not about bugs or features. It was about architecture. Linux put the entire operating system into one big program running with full privileges, and to Tanenbaum that was a design the field had already moved beyond. He told Torvalds to be thankful he was not his student, because such a design would not earn a high grade.
Torvalds answered sharply, others joined in, and the thread became one of the most quoted arguments in computing. By most practical measures, Torvalds won. Linux now runs most of the world’s servers, all of the world’s top supercomputers and, through Android, billions of phones. Yet the question Tanenbaum raised never went away, and over the following three decades the industry quietly kept moving toward his answer, piece by piece, without ever admitting that the debate had been reopened.
This essay is about that question. It sounds like a matter of taste, but it decides what happens when a driver has a bug, how fast a file can be read, whether a kernel can be mathematically proven correct, and why a single bad update in July 2024 stopped airlines, hospitals and banks around the world.
The privilege problem
Every operating system has a kernel: the part that runs in the processor’s privileged mode, with unrestricted access to memory and hardware. Everything else runs in user mode, inside the protective walls that the kernel maintains. That arrangement creates a sharp asymmetry. A bug in a user program crashes that program. A bug in the kernel can crash, corrupt or compromise the entire machine, because there is nothing underneath to catch it.
So the question “what belongs in the kernel?” is really a question about how much code you are willing to trust absolutely. There are two classic answers.
A monolithic kernel puts nearly all operating system services in privileged mode: process scheduling, memory management, file systems, the network stack and the device drivers. They all share one address space and call each other with ordinary function calls. Unix was built this way, and so are Linux and the BSDs.
A microkernel keeps only the bare minimum in privileged mode, usually address spaces, threads, a little scheduling and a mechanism for passing messages. Everything else, including file systems, network protocols and drivers, runs as ordinary user-mode processes called servers. When an application wants to read a file, it sends a message to the file server, which may in turn send a message to the disk driver, and the answers travel back the same way.
The idea is older than either Linux or MINIX. Per Brinch Hansen’s RC 4000 system in 1969 was built around a small “nucleus” that offered message passing and left the rest of the system to processes running on top of it. Brinch Hansen’s goal was flexibility: different operating system policies could run side by side on the same nucleus. Reliability and security arguments came later, but they became the heart of the case.
The case for small
The microkernel argument is, at bottom, an argument about failure. Large programs have bugs, and the bugs are not evenly distributed. A widely cited study by Andy Chou and colleagues at Stanford, published in 2001, ran automated checkers over Linux and found that device drivers had error rates three to seven times higher than the rest of the kernel. Two years later, a team at the University of Washington reported that drivers were responsible for about 85 percent of recently reported Windows XP crashes. Drivers are written by thousands of different vendors under deadline pressure, for hardware that is often poorly documented, and many of them are rarely exercised on any given machine. In a monolithic kernel, every one of them runs with the power to bring down everything.
In a microkernel system, a driver is just a process. If it dereferences a bad pointer, it crashes the way any program crashes, and the rest of the system keeps running. A supervisor can notice and restart it. MINIX 3, the redesign Tanenbaum’s group released in 2005, made this its signature feature: a “reincarnation server” that watches drivers and system servers and silently restarts any that fail. In demonstrations, researchers injected thousands of faults into running drivers, and the system recovered from them without the user noticing more than a brief pause.
In a monolithic kernel, the most fragile code on the machine runs with the most power. Microkernels exist to reverse that.
There is a security version of the same argument. The trusted computing base of a system is the code that must be correct for the system to be secure. In a monolithic kernel, that includes every driver and every file system loaded into it, which on a modern Linux machine can mean millions of lines. In a microkernel, the privileged core might be ten or twenty thousand lines. A vulnerability in the network server is still serious, but it gives an attacker control of the network server, not the machine.
The price of a message
If the case for microkernels is so clean, why does nearly everyone run a monolithic or hybrid kernel? The short answer is performance, and the story of how microkernels earned their reputation for slowness runs through one project in particular.
Mach, developed at Carnegie Mellon University from the mid-1980s, was the most ambitious microkernel of its era and for a while the most influential. It was meant to be the foundation for the next generation of operating systems, and it attracted serious commercial interest. But systems built on Mach ran noticeably slower than their monolithic equivalents. The cause was inter-process communication. In a monolithic kernel, a file system calling the disk driver is a function call that costs a few nanoseconds. In Mach, the same interaction was a message, and sending a message meant trapping into the kernel, validating rights, copying data, switching address spaces, scheduling the receiver and then doing all of it again for the reply. Each round trip could cost many microseconds, and a single application request might involve several of them.

Mach’s reputation did lasting damage. When Tanenbaum and Torvalds argued in 1992, “microkernel” already suggested “elegant but slow” to many working programmers, and Mach was the reason. The GNU project’s own kernel, the Hurd, which began on top of Mach in 1990, remains a working but niche system more than three decades later. Its difficulties are often cited as evidence that the multi-server design is simply too hard to get right.
Liedtke’s answer
The rebuttal came from a German researcher, Jochen Liedtke. His argument, laid out in a 1995 paper called “On µ-Kernel Construction,” was that microkernels were not inherently slow; Mach was. It had grown large and general, and its message passing had accumulated features, checks and copies that each looked reasonable and together were ruinous. Liedtke built a kernel called L4 around a strict principle: a feature belongs in the microkernel only if leaving it out would make it impossible to build the required system on top. Everything else goes outside. He then optimized message passing obsessively, down to choosing which registers carried the message and arranging data structures around the processor’s caches. The resulting IPC was roughly twenty times faster than Mach’s.
L4 did not take over the desktop, but it quietly took over a great many other places. Variants of it have run on the baseband processors of large numbers of mobile phones and in the secure enclave of Apple’s chips. More importantly, it showed that the performance gap between the two architectures was an engineering problem, not a law of nature. What remained was the cost of building and maintaining a full system out of separate servers, and that cost turned out to be the more stubborn one.
Why the monolith won anyway
Torvalds’ defense of Linux in 1992 was pragmatic rather than theoretical. A monolithic kernel was simpler to write, easier to debug and faster on the hardware people actually owned. Linux was also not quite as rigid as Tanenbaum suggested. It soon gained loadable kernel modules, so that drivers and file systems could be added to a running kernel without recompiling. The kernel stayed monolithic in its privileges but became modular in its structure.
Over time, the development process mattered as much as the architecture. Linux grew into one of the largest collaborative software projects in history, with thousands of contributors per release and tens of millions of lines of code, most of it drivers. Its maintainers developed strong conventions: drivers live in the main source tree, the internal interfaces change freely, and anyone who changes an interface fixes every driver that uses it. That discipline, more than any architectural purity, is what keeps Linux’s enormous privileged codebase working. It is a social solution to a problem that microkernels try to solve technically.
The other major desktop systems ended up somewhere in between. Windows NT, designed by Dave Cutler’s team and released in 1993, borrowed heavily from microkernel thinking, with subsystems running as separate components and a layered structure. In NT 4.0, released in 1996, Microsoft moved the window manager and graphics code into kernel mode because the message passing between them and applications had become a bottleneck. Apple’s XNU kernel, inherited from NeXT, is built on Mach but runs Mach and a large BSD Unix layer together in a single privileged address space, keeping Mach’s abstractions while discarding most of its message-passing overhead. Both are usually called hybrid kernels. A blunter description would be monolithic kernels with a microkernel’s vocabulary.
Where today’s kernels sit
| Kernel | Design |
|---|---|
| Linux | Monolithic, with loadable modules. Runs servers, Android, embedded devices and supercomputers. |
| FreeBSD, OpenBSD | Monolithic, in the classic Unix tradition. |
| Windows NT | Hybrid. Microkernel-inspired layering, with most services, including graphics, in kernel mode. |
| XNU (Apple) | Hybrid. Mach and BSD in one privileged address space; newer drivers increasingly in user space. |
| QNX | Microkernel. Real-time, widely used in cars and industrial systems. |
| seL4 | Microkernel of the L4 family, with a machine-checked proof of correctness. |
| Zircon (Fuchsia) | Microkernel. Google’s system, shipped on smart displays since 2021. |
| MINIX 3 | Microkernel. Runs inside the management engine of many Intel chipsets. |
The last line of that table hides one of the field’s better ironies. From around 2015, Intel’s Management Engine, the small independent computer embedded in many of its chipsets, has run a version of MINIX 3. When this became widely known in 2017, Tanenbaum wrote an open letter noting, with some amusement, that his system was probably the most widely used operating system on Intel computers. Intel had never told him. The microkernel had won after all, in a place almost no user would ever see.
Proving a kernel correct
The strongest argument for small kernels arrived in 2009, and it was not about speed or fault isolation. A team at NICTA in Sydney, led by Gerwin Klein and Gernot Heiser, announced that they had formally verified seL4, a microkernel of the L4 family. They had not tested it extensively, or audited it carefully. They had produced a machine-checked mathematical proof that its C implementation, about ten thousand lines of it, behaved exactly as its formal specification said it would, in every possible execution.
The practical meaning is striking. For the properties covered by the proof, whole classes of bugs simply cannot exist in seL4: no buffer overflows, no null pointer dereferences, no memory leaks in the kernel, no code paths that do something other than what the specification allows. Later work extended the proof down to the compiled binary and up to security properties such as isolation between components. The proof itself was many times larger than the code and took many person-years of effort, which is exactly why it was only possible for a microkernel. Nobody knows how to do the same for twenty million lines of Linux.
Testing shows that bugs exist. A proof shows that, for the properties it covers, they cannot.
The approach has been tested in the field in a memorable way. In DARPA’s HACMS program in the mid-2010s, researchers rebuilt the mission software of an unmanned Boeing helicopter on top of seL4. A professional red team was given access to the system, including the ability to run its own code in one of the components, and asked to take control of the aircraft. It could not break out of the component it had been given. Small kernels had always promised that a compromise could be contained. Here was a demonstration on something that flew.
The day the kernel fell over
On 19 July 2024, the security company CrowdStrike pushed a routine content update to its Falcon sensor, an endpoint protection product installed on millions of Windows machines. The sensor included a kernel-mode driver, and the update contained data that caused it to read memory out of bounds. Because the faulty code was running in the kernel, the result was not a crashed application but a crashed operating system. Microsoft later estimated that about 8.5 million Windows devices failed. Many of them crashed again on every reboot, because the driver loaded early in startup. Flights were grounded, hospitals postponed procedures, broadcasters went off the air and payment systems failed across several continents. Recovery often meant a technician physically booting each machine into safe mode to delete a single file.
It is hard to imagine a clearer illustration of Tanenbaum’s original point. The bug was not in Windows. It was in third-party code that Windows had allowed to run with full privileges, because security products want deep visibility into the system and the kernel was the only place to get it. In a system where that component ran as an isolated user-mode server, the same mistake would have crashed one service, which could have been restarted.
The response was telling. In the months that followed, Microsoft began working with security vendors on ways to let their products run outside the kernel, and it described the goal as making it possible for such software to work without kernel-mode drivers at all. Nobody called this a microkernel strategy. In effect, that is what it was.
The quiet convergence
Look at the major operating systems today and a pattern appears. None of them has converted to a pure microkernel. All of them are moving functionality out of privileged mode, or putting stronger walls around what stays in it.
Apple’s DriverKit, introduced in 2019, moves many classes of device drivers out of the macOS kernel into user-space processes. Windows has long run many drivers through its User-Mode Driver Framework, and its graphics stack can now recover from a crashed display driver by resetting it instead of crashing the whole system. Linux supports user-space file systems through FUSE, gives high-performance networking and storage applications direct access to devices through frameworks such as VFIO and DPDK, and runs small, sandboxed eBPF programs inside the kernel only after a verifier has checked that they cannot crash it or loop forever. Since late 2022 Linux has also accepted code written in Rust, a language designed to rule out at compile time many of the memory errors that make kernel bugs so dangerous.
Each of these is a partial answer to the same problem that Brinch Hansen, Tanenbaum and Liedtke were working on. Privileged code is dangerous; there is too much of it; something has to be done. The monolithic camp’s response has not been to adopt the microkernel design wholesale, which would mean rewriting decades of working code. It has been to chip away at the edges, moving out what can be moved, and to make what remains safer through verification, sandboxing and better languages.
Perhaps the most honest conclusion is that both sides of the 1992 argument were right about different things. Torvalds was right that a working, fast, practical kernel in the hands of a large community would beat an elegant design that was harder to build. Tanenbaum was right that putting every driver into the most privileged part of the system was a bet against reliability, and that the bill would eventually arrive. It arrived slowly, through countless crash reports and security advisories, and then all at once on a Friday morning in July 2024. The argument never ended because the trade-off never went away. Every operating system still has to decide, for each line of code it runs, how much it is willing to trust it. ■
Further reading
- Chris DiBona, Sam Ockman and Mark Stone, eds. Open Sources: Voices from the Open Source Revolution. O’Reilly, 1999. Includes the Tanenbaum–Torvalds exchange as an appendix.
- Per Brinch Hansen. “The Nucleus of a Multiprogramming System.” Communications of the ACM, 13(4), 1970.
- Jochen Liedtke. “On µ-Kernel Construction.” Proceedings of the 15th ACM Symposium on Operating Systems Principles (SOSP), 1995.
- Andy Chou, Junfeng Yang, Benjamin Chelf, Seth Hallem and Dawson Engler. “An Empirical Study of Operating Systems Errors.” SOSP, 2001.
- Michael M. Swift, Brian N. Bershad and Henry M. Levy. “Improving the Reliability of Commodity Operating Systems.” SOSP, 2003.
- Gerwin Klein et al. “seL4: Formal Verification of an OS Kernel.” SOSP, 2009.
- Jorrit N. Herder, Herbert Bos, Ben Gras, Philip Homburg and Andrew S. Tanenbaum. “MINIX 3: A Highly Reliable, Self-Repairing Operating System.” ACM SIGOPS Operating Systems Review, 40(3), 2006.
- CrowdStrike. “Channel File 291 Incident: Root Cause Analysis.” August 2024.
Research work by Merjen Kakajanova student of International University for the Humanities and Development. Instructor Nurmyrat Allayarov.





