YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
PoC: OOB read in Samsung ONE luci CircleConst loader via const-dims/buffer mismatch (CWE-190/125)
Importing a crafted .circle model reads out of bounds when materializing a constant tensor.
Root cause
compiler/luci/import/src/Nodes/CircleConst.cpp:
uint32_t num_elements = 1;
for (uint32_t r = 0; r < const_dims.size(); ++r)
num_elements = num_elements * const_dims[r]; // L247-251: unguarded uint32 product of attacker dims
...
copy_data<loco::DataType::FLOAT32>(buffer, num_elements, const_node); // L267
// copy_data<T>():
assert(raw_data.size() == num_elements * sizeof(T)); // L65: the ONLY guard โ compiled out in RELEASE (NDEBUG)
const T *data = reinterpret_cast<const T*>(raw_data.data());
for (uint32_t i = 0; i < num_elements; ++i)
const_node->at<DT>(i) = data[i]; // L70: reads data[i] past raw_data -> OOB read
num_elements is the product of the const tensor's dimensions (attacker-controlled), while raw_data
is the tensor's embedded buffer. A crafted const tensor that declares more elements (via its dims) than
its buffer holds makes the loop read past the buffer. The only check is the assert, which release
builds strip (NDEBUG) โ so production builds read out of bounds on a normal model import. The
unguarded uint32 product can also overflow, masking the size mismatch.
Reproduce (AddressSanitizer, RELEASE build)
circle_circleconst_oob_read_harness.cpp reproduces copy_data verbatim; build with -DNDEBUG so the
assert is stripped (as in release):
g++ -DNDEBUG -fsanitize=address -g -O0 circle_circleconst_oob_read_harness.cpp -o poc && ./poc
# release build: assert stripped -> copy_data reads data[0..4096) past a 4-float buffer
# ==ERROR: AddressSanitizer: heap-buffer-overflow READ of size 4
# #0 copy_data<float> ... 0x... is located 0 bytes after 16-byte region <- raw_data buffer
A real trigger is a .circle const tensor whose shape dims declare more elements than its buffer.
Fix
Validate raw_data.size() == num_elements * sizeof(T) (and guard the dims product against overflow) with
a real runtime check that returns an error โ not an assert that release builds remove.