guest@6admin.io:~$

Containers, micro-VMs and Firecracker: why isolation is not what you think

A Docker container is not a VM. It is a process with namespaces. The kernel is shared: the same Linux, the same syscall table, the same kernel code, the same network stack. A kernel vulnerability opens ALL containers on the machine, not just one.

This is a distinction the articles on this blog have documented since 2006: the chroot that overflows via a symlink, the raw socket that sees the entire network, the socket speaking TCP because the kernel does the transport. Each of these techniques works because container isolation is sharing, not a hardware boundary.

The isolation chain, weakest to strongest

Process        → no isolation (one process can kill the others)
Chroot         → filesystem isolation by path (symlink escape)
Namespaces     → kernel isolation by type (pid, net, mnt, user)
+ seccomp      → syscall filtering
+ AppArmor/SELinux → mandatory access control
+ cgroups      → resource capping
──────────────────────────────────────────────────────────────
= Container (Docker, Podman): all of the above, same kernel
──────────────────────────────────────────────────────────────
Micro-VM (Firecracker)  → hardware isolation (Intel VT-x, AMD-V)
VM (KVM, Hyper-V)       → hardware isolation + hypervisor
Physical machine        → hardware isolation

The container stacks kernel mechanisms: namespaces for view isolation, seccomp for syscall filtering, AppArmor/SELinux for mandatory access control, cgroups for resources. Each layer is a kernel filter. The kernel is the referee AND the playground: a kernel vulnerability bypasses all layers simultaneously.

The kernel vulnerability: the container’s Achilles heel

Dirty COW (CVE-2016-5195), Dirty Pipe (CVE-2022-0847), CVE-2022-0185 (container escape via legacy_parse_param), CVE-2024-1086 (nf_tables use-after-free): every kernel vulnerability is a potential container escape. They work BECAUSE the kernel is shared: the container executes syscalls in the same kernel as the host and a kernel memory corruption from the container contaminates the host.

Mitigations exist (seccomp to reduce syscall surface, AppArmor for access control, user namespaces for UID mapping), but they are kernel-based: a kernel vulnerability bypasses them all. This is the fundamental difference between software isolation (kernel) and hardware isolation (VT-x, AMD-V).

The micro-VM: VM-level isolation at container speed

Firecracker (AWS) creates micro-VMs that boot in ~125 ms with ~5 MB of memory overhead. Each micro-VM has its OWN kernel, isolated by KVM (Intel VT-x / AMD-V), without console, without SSH, without systemd: just the application binary.

The difference from a container:

  • Dedicated kernel: each micro-VM has its own kernel, isolated by hardware. A kernel vulnerability in one micro-VM does NOT contaminate the host or other micro-VMs.
  • Minimal surface: no shell, no SSH, no network daemon. The process, the minimal kernel and nothing else.
  • Fast boot: 125 ms, versus several seconds for a full VM or several minutes for bare-metal provisioning.

Unikernels (MirageOS, Unikraft, OSv) go further: a single-purpose kernel compiled with the application, no userspace, no shell, no generic syscall table. The attack surface shrinks to the minimum needed.

What it changes

The container remains the right tool for orchestration (Kubernetes, volumes, networking). The micro-VM is the right tool for isolation (multi-tenant, serverless, untrusted code). They are not mutually exclusive: Kata Containers run containers inside micro-VMs and Firecracker is Fargate’s VMM.

But if your threat model includes kernel vulnerabilities, a container alone is not enough. The nf_tables vulnerability that enables a chroot escape via symlink, or Dirty Pipe that writes to read-only files, work in containers AND chroots. Hardware isolation (VT-x) cannot be bypassed by a guest kernel bug: the hypervisor is a different boundary, in a different execution ring.