  Fuzzing is one of the most effective approaches to finding software flaws.
However, applying it to microcontroller firmware incurs many challenges. For
example, rehosting-based solutions cannot accurately model peripheral behaviors
and thus cannot be used to fuzz the corresponding driver code. In this work, we
present $\mu$AFL, a hardware-in-the-loop approach to fuzzing microcontroller
firmware. It leverages debugging tools in existing embedded system development
to construct an AFL-compatible fuzzing framework. Specifically, we use the
debug dongle to bridge the fuzzing environment on the PC and the target
firmware on the microcontroller device. To collect code coverage information
without costly code instrumentation, $\mu$AFL relies on the ARM ETM hardware
debugging feature, which transparently collects the instruction trace and
streams the results to the PC. However, the raw ETM data is obscure and needs
enormous computing resources to recover the actual instruction flow. We
therefore propose an alternative representation of code coverage, which retains
the same path sensitivity as the original AFL algorithm, but can directly work
on the raw ETM data without matching them with disassembled instructions. To
further reduce the workload, we use the DWT hardware feature to selectively
collect runtime information of interest. We evaluated $\mu$AFL on two real
evaluation boards from two major vendors: NXP and STMicroelectronics. With our
prototype, we discovered ten zero-day bugs in the driver code shipped with the
SDK of STMicroelectronics and three zero-day bugs in the SDK of NXP. Eight CVEs
have been allocated for them. Considering the wide adoption of vendor SDKs in
real products, our results are alarming.
