YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
PoC: heap OOB write in Samsung/ONE luci-interpreter Unpack kernel via out-of-range axis (CWE-787/122)
Loading a crafted Circle model (.circle) with an Unpack op whose axis equals the input rank (one past
the valid range) overflows the output-shape vector in the luci-interpreter Unpack kernel's configure().
Root cause
compiler/luci-interpreter/src/kernels/Unpack.cpp:38-51:
int axis = _params.axis; // loader: params.axis = node->axis() (no check)
if (axis < 0) axis += input()->shape().num_dims();
assert(axis >= 0 && axis < input_shape.num_dims()); // :43 (stripped in release / NDEBUG)
Shape output_shape(input_shape.num_dims() - 1); // std::vector<int32_t> of size N-1
int out_index = 0;
for (int in_index = 0; in_index < input_shape.num_dims(); ++in_index)
if (in_index != axis)
output_shape.dim(out_index++) = input_shape.dim(in_index); // :50
axis is read straight from the Circle flatbuffer (loader/nodes/Unpack.cpp:36 params.axis = node->axis())
with no validation; the only guard is the assert at :43, which release builds strip. With axis == num_dims
(one past valid 0..N-1), the test in_index != axis is always true, so out_index increments N
times and the final write is output_shape.dim(N-1) on a Shape of size N-1. Shape::dim (core
Tensor.h:47-51) returns _dims[i] via std::vector::operator[] guarded only by a (stripped) assert, so
dim(N-1) is a one-past-end heap OOB write. Reachable at configure() time on the normal model-load
path. Distinct from the filed importer bugs and from the StridedSlice kernel bug.
Reproduce (AddressSanitizer)
g++ -fsanitize=address -g -O0 circle_unpack_oob_write_harness.cpp -o poc && ./poc
# input rank N=3; attacker axis=3 (assert axis<N stripped); output_shape size = 2
# loop writes output_shape.dim(out_index) with out_index reaching 2 ...
# ==ERROR: AddressSanitizer: heap-buffer-overflow WRITE of size 4 ... 0 bytes after the 8-byte region
Fix
Replace the assert with a hard runtime check that throws when axis < 0 || axis >= input_shape.num_dims()
before allocating/looping (validate the Unpack axis in the loader as well).