Repository navigation
Prior Art on Model and Register Fuzzing
Reverse-engineering proprietary, closed-source Neural Processing Unit (NPU) accelerators and their specialized compiler toolchains requires a multi-tiered approach. Rather than relying solely on trial-and-error, we can draw upon established methodologies in academic compiler testing, binary security research, and hardware driver development.
This document surveys the state-of-the-art prior art across three distinct abstraction levels and outlines how these techniques are mapped directly to the RKNPU2 / RK3588 ecosystem inside the ork-driver project.
Reverse-engineering proprietary NPU hardware is not just a quest for technical documentation; it is driven by critical performance bottlenecks and architectural limitations of closed-source vendor solutions. Our primary motivations for performing structure-aware fuzzing on the RKNPU2 / RK3588 platform include:
-
Closing the Prefill Performance Gap: Currently, the closed-source
librkllmrtandlibrknnrtruntimes prefill models significantly faster than our open-source implementation. They achieve this through highly optimized, proprietary hardware scheduling that remains undocumented. -
Enabling High-Performance Mixture-of-Experts (MoE): Edge NPUs enforce static tensor shape compilation, which clashes with the dynamic, sparse routing of MoE models. By fuzzing NPU registers, we aim to uncover the low-level equations required to trigger multi-batch/3D-tensor operations (like a native hardware-accelerated
BatchMatMul) in a single hardware submission, avoiding slow, fragmented CPU-driven expert dispatches. -
Resolving Memory Roundtrips (Output Zero-Copy): Currently, input zero-copy is functional, but output zero-copy (
ORK_ZC_OUT=1) returns corrupted activations. Fuzzing the Post-Processing Unit (PPU) allows us to map the output stride and base address registers (0x4020and0x4024) under multi-core dispatches, eliminating redundant host-to-device memory copy bottlenecks. -
Achieving a Fully Open, Autonomic NPU Stack: By replacing closed, proprietary user-space binary blobs with
ork-driver(a clean-room, C-based userspace library communicating directly over the kernel's DRM interfaces), we guarantee a fully transparent, highly maintainable compiler/runtime path that integrates seamlessly with open ecosystems (such asllama.cppandggml-ork).
Compilers for deep learning accelerators are highly sensitive to graph topology. If a computational graph contains disconnected nodes, cycles, or dimension mismatches, the compiler's early verification passes will reject the input before it reaches the optimization and register-lowering stages.
-
NNSmith (ASPLOS '23): State-of-the-art framework for deep learning compiler fuzzing.
- The SMT-Constraint Approach: Instead of blindly mutatively combining layers, NNSmith utilizes a Satisfiability Modulo Theories (SMT) solver (such as Z3) to solve for valid tensor shapes, strides, and operator parameters (padding, kernel sizes, channels). This ensures that every generated computational graph is both syntactically and semantically valid.
- Differential Testing: NNSmith executes the same generated graph across multiple backends (e.g., CPU interpreter vs. NPU compiled engine) and compares outputs. Discrepancies point to optimizer or compilation lowering bugs.
-
Muffin (ICSE '22) & Lemon (ISSTA '20):
- Graph Mutation Operators: These frameworks define specific, high-level structural mutations such as node insertion, node removal, layer swapping, and tensor slicing. They maintain a strict type-and-dimension-propagation engine to heal the graph's connections after a mutation occurs.
Once a model is compiled, it is serialized into a proprietary binary format (such as .rknn, Apple CoreML's compiled bundles, or Google's Edge TPU .tflite compiled blobs). These files are consumed by closed-source user-space runtimes (like librknnrt.so).
-
Structure-Aware Fuzzing (AFL++ / LibAFL):
- Custom Grammar Mutators: Standard byte-level mutations (bit-flipping) are highly inefficient on structured containers with magic numbers, checksums, and nested offset tables. Prior art utilizes custom mutators written in C/C++ or Python that understand the layout structure (e.g., Protobuf or FlatBuffers specifications). This allows mutations to target deep data payloads (like quantization scales or weights) without invalidating the file's structural integrity.
-
Virtual Execution & Taint Analysis (Unicorn / Triton / PANDA):
-
Control-Flow Mapping: Researchers use CPU emulators (e.g., Unicorn Engine) to run the closed-source model loader library in isolation. By hooking memory accesses and system library boundaries, they track how specific bytes in the model file flow into allocation sizes (
malloc) and driver-submission structures. This is used to map undocumented file format headers and extract embedded intermediate representations.
-
Control-Flow Mapping: Researchers use CPU emulators (e.g., Unicorn Engine) to run the closed-source model loader library in isolation. By hooking memory accesses and system library boundaries, they track how specific bytes in the model file flow into allocation sizes (
At the lowest level, the user-space runtime translates the model's graph structure into physical register-programming command streams (regcmd) sent via ioctl to the kernel driver.
-
NVIDIA's NVDLA (NVIDIA Deep Learning Accelerator) Reference:
- Architectural Lineage: The Rockchip RK3588's NPU frontend and tensor cores are closely derived from NVIDIA's open-source NVDLA hardware IP.
-
Prior Art Application: The register space, register boundaries, and memory-layout paradigms of NVDLA are fully documented in the public domain. This serves as a vital blueprint for understanding the structural partitions of our three target blocks:
-
CNA (Convolution/Channel Neural Accelerator): Matches NVDLA's convolution buffer control registers (
0x0201). -
DPU (Data Processor Unit): Matches NVDLA's activation/pooling and matrix execution pipelines (
0x0801). -
PPU (Post-Processing Unit): Matches NVDLA's element-wise scaling and memory/DMA output streaming blocks (
0x1001).
-
CNA (Convolution/Channel Neural Accelerator): Matches NVDLA's convolution buffer control registers (
-
Blacklist & Power-Cycle Guarded Sweeps (
i4_multim_fuzz.cstyle):-
Defensive Fuzzing Loops: Prior art in hardware security testing (such as fuzzing PCIe registers or SoC peripherals) implements strict state boundaries. Since executing a malformed register write can cause the hardware to wedge (locking up the NPU core or triggering kernel-panic reboots), the test runner must persist state out-of-band:
-
State Serialization: Write active register, target offset, and mutated value to a local file (
fuzz_progress.txt) before executingioctl. -
Hardware Blacklisting: If the board hangs or reboots, the boot script reads
fuzz_progress.txtand appends the offending register tofuzz_blacklist.txtto bypass it on subsequent attempts. - Out-of-Band Power Recovery: Automating the physical power-cycle of the hardware board using network-controlled smart plugs (such as Home Assistant switch APIs) to recover the fuzzer seamlessly.
-
State Serialization: Write active register, target offset, and mutated value to a local file (
-
Defensive Fuzzing Loops: Prior art in hardware security testing (such as fuzzing PCIe registers or SoC peripherals) implements strict state boundaries. Since executing a malformed register write can cause the hardware to wedge (locking up the NPU core or triggering kernel-panic reboots), the test runner must persist state out-of-band:
Within ork-driver, we utilize a hybrid strategy that combines elements from all three tiers to reverse-engineer undocumented features (like INT4 Multi-M matrix operations) and optimize memory layouts (like Output Zero-Copy).
┌───────────────────────────────┐
│ 1. SMT / Graph-Level Fuzzing │ (Generates valid ONNX/TFLite models)
└───────────────┬───────────────┘
│ (rknn-toolkit2 compiler)
┌───────────────▼───────────────┐
│ 2. Binary Interposition / RE │ (Captures ioctl regcmd payload)
└───────────────┬───────────────┘
│ (regcmd extraction)
┌───────────────▼───────────────┐
│ 3. Silicon-Level Regcmd Sweep │ (Dispatches mutations directly)
└───────────────────────────────┘
Instead of reverse-engineering the .rknn compiler directly, we use the official rknn-toolkit2 compiler as a black-box oracle.
- We use an abstract graph generator (following the NNSmith/Muffin paradigm) to produce diverse, valid models containing our target operators (e.g., MatMul, BatchMatMul, GroupedGEMM) in ONNX format.
- We compile these ONNX models into
.rknnbinaries using the official toolkit. - We execute the compiled
.rknnfiles throughlibrknnrt.sowithORK_TRACE=1active, dumping the raw, valid hardwareregcmdtemplates directly. - By comparing the register diffs between a single
MatMuland a multi-batchBatchMatMul, we identify the specific control registers that handle batch size, weight offsets, and strides.
Once we have a valid regcmd template, we use the Structure-Aware Register Sweep approach implemented in tools/i4_multim_fuzz.c:
- Protect Essential Registers: We mark all DMA address registers, memory boundaries, and execution trigger registers as essential (immutable) so the fuzzer does not overwrite pointers and trigger kernel page faults.
-
Target Unknown Ranges: We select unmapped gaps in the CNA (
0x0201), DPU (0x0801), and PPU (0x1001) register spaces. - Perform Sweeps with Safety Guards: We iterate through candidate values (strides, scaling factors, batch limits) and dispatch the mutated instruction stream.
- Automatic Recovery: If a register write wedges the NPU, our out-of-band Home Assistant integration power-cycles the board, blacklists the offending offset, and continues the sweep automatically.