| # onnx-tensorrt convertAxis inclusive-bound OOB write (Split + Resize) |
|
|
| Root cause: `convertAxis` (importerUtils.cpp:306-317) validates an axis with an |
| INCLUSIVE upper bound `axis >= 0 && axis <= nbDims`. The `<= nbDims` was relaxed to |
| support `QuantDequantLinearHelper` (see the in-source comment). For an input of rank |
| R, an attacker-supplied `axis == R` therefore PASSES validation, and is then used to |
| index a `std::vector` sized exactly R, producing a one-element out-of-bounds WRITE |
| (`std::vector::operator[]` does no bounds check in a release build). |
|
|
| Pinned commit: `7c51a63a719180eb5160c874c111746f3fb46a6b` |
|
|
| ## Instances (one consolidated finding) |
|
|
| | Instance | Site | Vector | Element written OOB | |
| |---|---|---|---| |
| | Split (headline, High) | onnxOpImporters.cpp:6350-6354 | `std::vector<int64_t> tmp(inputDims.size())` | int64 | |
| | Resize / scales | onnxOpImporters.cpp:5233-5235 + 5413-5417 | `std::vector<float> tempVec(inputRank, 1.0)` | float | |
| | Resize / sizes | onnxOpImporters.cpp:5233-5235 + 5341-5344 | `std::vector<int64_t> tempVec(inputDims...)` | int64 | |
|
|
| The static Resize checker (onnxOpCheckers.cpp:672-718) validates only mode and axis |
| uniqueness, NOT axis vs rank, so there is no upstream pre-filter for the Resize path. |
|
|
| ## Files |
|
|
| - `harness.cpp` — faithful standalone ASan harness. Copies `convertAxis` verbatim |
| (with the `<= nbDims` bound) and reproduces the exact `vec[axis] = value` writes from |
| Split :6354, Resize/scales :5417, Resize/sizes :5344, driven by `axis == rank`. |
| - `make_onnx.py` — builds the three crafted `.onnx` PoC models (input rank 3, offending |
| axis/axes == 3). |
| - `poc_split_axis_eq_rank.onnx`, `poc_resize_scales_axes_eq_rank.onnx`, |
| `poc_resize_sizes_axes_eq_rank.onnx` — the crafted inputs an attacker would feed to |
| the parser. |
| - `asan_split.txt`, `asan_resize_scales.txt`, `asan_resize_sizes.txt` — captured ASan |
| heap-buffer-overflow reports. |
|
|
| ## Build & run |
|
|
| ``` |
| clang++ -std=c++17 -g -O1 -fsanitize=address -fno-omit-frame-pointer \ |
| -U_GLIBCXX_ASSERTIONS -U_FORTIFY_SOURCE -D_GLIBCXX_NO_ASSERTIONS \ |
| harness.cpp -o harness |
| export ASAN_OPTIONS=detect_leaks=0 |
| ./harness split # heap-buffer-overflow WRITE size 8, 0 bytes after 24-byte region |
| ./harness resize-scales # heap-buffer-overflow WRITE size 4, 0 bytes after 12-byte region |
| ./harness resize-sizes # heap-buffer-overflow WRITE size 8, 0 bytes after 24-byte region |
| ./harness split-control # axis < rank -> clean, no overflow |
| ``` |
|
|
| The libstdc++ hardening flags are turned OFF to match how upstream onnx-tensorrt is |
| compiled (release, no `_GLIBCXX_ASSERTIONS`), so `operator[]` performs a raw pointer |
| write and ASan observes the true heap overflow rather than a container assertion. |
|
|
| ## Harness faithfulness (stated honestly) |
|
|
| The vulnerable expressions are byte-for-byte the real lines: the `convertAxis` body |
| including the `axis <= nbDims` bound, the vector sizing (`inputDims.size()` / |
| `inputRank`), and the indexed writes. The only substitutions are the surrounding |
| TensorRT plumbing that does not participate in the bug: `ShapeTensor`/`ITensor`/ |
| `shapeOf` are represented by a `std::vector` whose `.size()` is the tensor rank |
| (exactly what `inputDims.size()` returns in the importer), and `ONNXTRT_CHECK_NODE` is |
| reduced to its throw-on-false semantic. Building full onnx-tensorrt requires TensorRT; |
| the harness compiles the real vulnerable lines verbatim and drives them with the |
| attacker-controlled `axis == rank` value that the crafted `.onnx` carries. |
|
|
| ## Distinctness |
|
|
| Root cause here = `convertAxis` inclusive bound (importerUtils.cpp:314) flowing into |
| fixed-size vectors in Split/Resize. Shares no line with the 4 previously filed |
| onnx-tensorrt findings (external_data `..` traversal; volume() int overflow; |
| parseExternalWeights offset OOB WeightsContext.cpp:212; GRU/RNN iterator OOB |
| onnxOpImporters.cpp:2825). No CVE exists for convertAxis axes OOB. |
| |