tensorrt-poc / README.md
ericblackgachara's picture
Upload 3 files
190a505 verified
|
Raw
History Blame Contribute Delete
3.61 kB
# TensorRT regionPlugin β€” NULL Pointer Dereference
![Severity: High](https://img.shields.io/badge/Severity-High%207.5%20CVSS-orange)
![CWE-476](https://img.shields.io/badge/CWE-476%20NULL%20Ptr%20Deref-red)
![CWE-789](https://img.shields.io/badge/CWE-789%20Unbounded%20Alloc-red)
![Status: Ready to submit](https://img.shields.io/badge/Status-Ready%20to%20Submit-blue)
## Target
| Field | Value |
|---|---|
| **Repository** | https://github.com/NVIDIA/TensorRT |
| **Platform** | huntr.com |
| **Max payout** | $4,000 |
| **Affected file** | `plugin/regionPlugin/regionPlugin.cpp` |
| **Affected lines** | `allocateChunk` template (38–42), deserialization ctor (93–227), loop (152–168) |
## Vulnerability
`allocateChunk<T>()` calls `malloc(count * sizeof(T))` with **no NULL check** on the return value. The `count` parameter (`smTreeTemp->n`) is read directly from an attacker-controlled deserialization buffer with no bounds validation.
Crafting a `.trt` engine file with `softmaxTree.n = INT32_MAX` causes:
1. `malloc(8,589,934,588)` β†’ fails β†’ returns `NULL`
2. Loop: `smTreeTemp->leaf[0]` β†’ WRITE to address `0x0` β†’ **SIGSEGV**
## Root Cause Snippet
```cpp
// regionPlugin.cpp:38-42 β€” BUG
template <typename T>
void allocateChunk(T*& ptr, int32_t count)
{
ptr = static_cast<T*>(malloc(count * sizeof(T)));
// ← no NULL check here
}
// regionPlugin.cpp:117, 121 β€” attacker-controlled n flows into allocateChunk
smTreeTemp->n = read<int32_t>(d); // ← 0x7FFFFFFF from crafted buffer
allocateChunk(smTreeTemp->leaf, smTreeTemp->n); // malloc(8.5 GB) β†’ NULL
// regionPlugin.cpp:156 β€” NULL dereference
smTreeTemp->leaf[i] = read<int32_t>(d); // WRITE to 0x0 β†’ SIGSEGV
```
## Trigger Path
```
crafted .trt file
β†’ Runtime.deserialize_cuda_engine(data)
β†’ RegionPluginCreator::deserializePlugin(name, serialData, serialLength)
β†’ new Region(serialData, serialLength) [regionPlugin.cpp:93]
β†’ allocateChunk(smTreeTemp->leaf, INT32_MAX) [regionPlugin.cpp:121]
β†’ malloc(8,589,934,588) returns NULL
β†’ smTreeTemp->leaf[0] = read<int32_t>(d) [regionPlugin.cpp:156]
β†’ SIGSEGV
```
## Reproduction
```bash
# Compile (no CUDA, no GPU, no TensorRT required)
g++ -std=c++17 -O0 -o poc_tensorrt poc_tensorrt.cpp
# Run
./poc_tensorrt
```
**Expected output:**
```
[*] n = 2147483647 (0x7FFFFFFF)
[*] malloc requested: 8589934588 bytes (8.0 GB)
[*] leaf ptr after allocateChunk: (nil)
[!] malloc FAILED β€” leaf is NULL
[!] Entering loop β€” crash on first iteration...
Segmentation fault (core dumped) [exit 139 / SIGSEGV]
```
**ASAN confirmation:**
```bash
g++ -std=c++17 -O0 -g -fsanitize=address -o poc_tensorrt_asan poc_tensorrt.cpp
ASAN_OPTIONS=allocator_may_return_null=1 ./poc_tensorrt_asan
# ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000
# The signal is caused by a WRITE memory access.
# Hint: address points to the zero page.
# #0 in trigger_deserialize poc_tensorrt.cpp:187
```
## Suggested Fix
```cpp
template <typename T>
void allocateChunk(T*& ptr, int32_t count)
{
ptr = static_cast<T*>(malloc(count * sizeof(T)));
PLUGIN_VALIDATE(ptr != nullptr); // ADD THIS
}
```
All 9 call sites in the deserialization constructor are fixed by patching the template.
## Files
| File | Description |
|---|---|
| `poc_tensorrt.cpp` | Self-contained C++ PoC β€” compiles with g++, no CUDA |
| `report.md` | Full huntr-format vulnerability report |
| `poc-evidence.html` | HTML evidence page with terminal output and ASAN backtrace |
| `README.md` | This file |