Why User-Space Emulation Hits a Wall
Most embedded Linux emulation runs in user space. A stock ARM or MIPS QEMU machine boots, the firmware unpacks into a chroot, and LD_PRELOAD shims fake missing peripherals. NVRAM is the classic case: a library like lib_nvram intercepts calls and returns plausible defaults. For single-binary work this is fine. But modern router firmware runs dozens of tightly coupled processes. When the architecture expects a holistic system, patching one library at load time cannot compensate for all the missing hardware.
Rehosting from the Kernel Up
The rehosting concept skips user space entirely. Feed the exact firmware image from a vendor update package to a custom kernel built for a compatible QEMU machine. The key insight is that vendors like Netgear, ASUS, and TP-Link buy SoCs from manufacturers like Broadcom, Qualcomm, and MediaTek. Those manufacturers supply the SDK and kernel code. By building a kernel that mimics a specific SoC’s environment, any firmware shipped for that chip runs without modification in user space.
Reading the Target Before Writing a Line
The ASUS AC87U, released in 2014 and based on Broadcom’s BCM4709 SoC, was the test device. No physical hardware was used. Everything came from public sources: firmware from the ASUS website and GPL code from the same page. Unblob unpacks the TRX firmware format cleanly, carving out the LZMA kernel and SquashFS filesystem without post-processing. A version string in the kernel blob reveals Linux 2.6.36.4, GCC 4.5.3, and boot arguments pointing to mtdblock2 as root with sbin/pre-init as the init binary.
Patching Kernel Gaps One Boot at a Time
The first boot attempt fails. The BCM4709 firmware compresses its SquashFS with XZ, but mainline Linux 2.6.36.4 has no XZ support for SquashFS; that arrived in 2.6.38. Broadcom’s GPL release includes a backported XZ patch. Applying it unblocks the filesystem. Flash layout needs the same care: a 64 MB image with MTD partitions named to match what pre-init expects, passed at boot via the mtdparts kernel argument. Both problems surface on the first run and take minutes to fix.
Kernel Stubs for NVRAM, GPIO, and Networking
With the filesystem mounted, NVRAM errors dominate. Lib_nvram uses plain read/write/ioctl calls on /dev/nvram. A kernel character device mirrors that interface, backed by a flash partition, giving user space persistent NVRAM without touching a single binary. GPIO errors get the same treatment: an ioctl-driven stub returning neutral pin states informed by device tree files. A second Ethernet interface requires an IRQ-mapped addition to the QEMU V-Express machine and a patched SMSC 911X driver that returns the correct physical-link status codes.
One SoC, Dozens of Devices
The finished environment boots the AC87U to a working system. SSH comes up. The web management interface loads and accepts logins. About 95% of functionality works; the only gap is an unemulated Quantenna co-processor for one wireless band. The same kernel runs D-Link and Netgear firmware immediately. Tenda devices use a different NVRAM format called CFM, a key-value store with a CRC32 header, but the same approach applies. Getting the first vendor running takes roughly a day. A second device on the same SoC takes about an hour.
Notable Quotes
themselves. They’re not chip companies. Sigusr Polke · ▶ 5:03
do a little bit of fraud in the kernel. Sigusr Polke · ▶ 29:56
4709 work basically immediately. Sigusr Polke · ▶ 34:04
It’s still early days proof of concept, Sigusr Polke · ▶ 37:18
Key Takeaways
- Kernel-level rehosting emulates stock firmware without LD_PRELOAD by building a compatible kernel instead.
- One SoC-targeted environment runs firmware from dozens of devices across multiple vendors simultaneously.
- NVRAM, GPIO, and network driver stubs are quick to write once user-space API behavior is mapped.
About the Speaker
Sigusr Polke is the single-use pseudonym of a security researcher who has spent a lot of time poking at embedded systems over the years.