EnigmaConsultant's picture
Upload folder using huggingface_hub
e4c8dd7 verified
|
Raw
History Blame Contribute Delete
2.67 kB

CoreML (apple/coremltools) MILBlob Span::Slice integer-overflow bounds-check bypass -> OOB read

PoC package for a heap/mapped out-of-bounds read in the CoreML weight-blob parser (MILBlob) shipped in apple/coremltools. A crafted .mlmodelc / weights.bin weight-blob file with attacker-controlled blob_metadata.offset and blob_metadata.sizeInBytes (both uint64) triggers a 64-bit integer overflow in the bounds check inside Span<T>::Slice(index, size), returning a Span whose Size() is enormous (here 2^64 - 50). A consumer reading the weight bytes then reads far past the mapped file.

Files

  • weights.bin - the malicious CoreML weight-blob file (384 bytes)
  • craft.py - script that generates weights.bin (documents the byte layout)
  • harness.cpp - ASan harness that drives the REAL StorageReader / MMapFileReader / Span
  • build.sh - build command (clang++ + ASan)
  • asan_crash.txt - the captured AddressSanitizer crash trace

Reproduce

git clone --filter=blob:none --sparse https://github.com/apple/coremltools.git
cd coremltools
git sparse-checkout set mlmodel/src/MILBlob
# commit pinned for this PoC: 3fb88603a6af3d12bf72ca2dcc0a3724a631317b

clang++ -std=c++17 -fsanitize=address -g -O0 -Imlmodel/src \
  harness.cpp \
  mlmodel/src/MILBlob/Blob/StorageReader.cpp \
  mlmodel/src/MILBlob/Blob/MMapFileReader.cpp \
  mlmodel/src/MILBlob/Blob/MMapFileReaderFactory.cpp \
  -o harness

python3 craft.py
ASAN_OPTIONS=detect_leaks=0 ./harness weights.bin

Root cause

mlmodel/src/MILBlob/Util/Span.hpp (~line 325):

Span<T> Slice(size_t index, size_t size) const
{
    MILVerifyIsTrue(size > 0 && index < Size() && index + size <= Size(), std::range_error, "index out of bounds");
    return Span<T>(Data() + index, size);
}

index + size is an unchecked 64-bit addition. With index = 100 and size = 2^64 - 50, index + size wraps to 50, which is <= Size(), so the check passes and an oversized Span is returned.

Both operands are attacker-controlled: StorageReader::Impl::GetRawDataView (StorageReader.cpp) calls m_reader->ReadData(metadata.offset, metadata.sizeInBytes), and MMapFileReader::ReadData (MMapFileReader.cpp) forwards straight to m_dataSpan.Slice(offset, length). The only validation on the metadata is the sentinel == 0xDEADBEEF check in GetMetadata - offset and sizeInBytes are never range-checked before reaching Slice.

Source availability

100% open source, BSD-3-Clause: https://github.com/apple/coremltools Vulnerable file: mlmodel/src/MILBlob/Util/Span.hpp.