Fix integer overflow in RKNPU implicit bias allocation
Description
The RKNPU execution provider's ONNX converter creates implicit (all-zero) bias
buffers when a Conv / Gemm / QLinearConv node omits its bias input. The
buffer size was computed as sizeof(T) * dim (where dim derives from a model
weight's shape) with no overflow check, and the raw allocation was tracked in a
manually-freed void* list.
This PR hardens the converter:
- Dimension validation: ONNX
int64_tdimensions are validated (via
ORT_ENFORCEin a newToRknpuDimhelper) before being narrowed to the RKNPU
uint32_tshape representation, rejecting negative or out-of-range values.
This covers all four ingestion points (HandleInitializer,
GetInputOfOnnxModel,GetShape,GetSupportedNodes). - Overflow-checked allocation: all four implicit-bias sites
(AddLayerConvImpl,AddLayerQLinearConvImpl,AddLayerDepthwiseConvImpl,
AddLayerFC) go through a sharedAllocZeroedBiashelper that computes the
byte count withSafeInt<size_t>(throws on overflow) and returns a
zero-initializedstd::make_unique<uint8_t[]>buffer. - RAII ownership:
free_list_is now
std::vector<std::unique_ptr<uint8_t[]>>, so the bias buffers are freed
automatically andClear()no longer walks/free()s raw pointers.
Motivation and Context
A malicious ONNX model can provide dimensions that are unsafe for the RKNPU
converter's 32-bit shape representation or for byte-size allocation arithmetic:
- ONNX stores dimensions as
int64_t, while the RKNPU converter/DDK uses
uint32_tshape values. Silently narrowing a large or negativeint64_t
value can produce a misleadinguint32_tdimension. - Even after a dimension is represented as
uint32_t, the original
sizeof(T) * dimcould overflowsize_ton 32-bit RKNPU targets. For example,
dim = 0x40000400makessizeof(float) * dimwrap to 4096 bytes while the
created tensor still advertisesdimelements, which would corrupt the heap
when the bias is consumed by the driver. - The original code also passed the
mallocresult tomemsetwithout a null
check.
The fix uses SafeInt<size_t> (the ORT-standard idiom for memory-size
arithmetic), validates ONNX dimensions before they enter the RKNPU uint32_t
shape model, and replaces the manual malloc/free list with zero-initialized,
RAII-owned std::make_unique<uint8_t[]> buffers.
Validation: the RKNPU EP requires the Rockchip DDK (RKNPU_DDK_PATH) and an
ARM target, so it does not build on a typical x64 dev box and has no GPU-free CI
leg. The change was validated with clang-format, git diff --check, and a
standalone test against ORT's SafeInt.hpp, confirming the guard throws on the
overflowing dimensions (0x40000400, 0xFFFFFFFF) while preserving normal and
zero-dimension behavior.
Testing: No unit test is included because the RKNPU EP is not compiled in
any CI leg (it requires the proprietary Rockchip DDK and an ARM target), and the
ToRknpuDim / AllocZeroedBias helpers have internal (file-static) linkage,
so they are not reachable from the gtest suites. The overflow/validation logic
was instead exercised with a standalone test against ORT's SafeInt.hpp as
noted above.