gltfio: EXT_meshopt_compression indices bypass cgltf validation → OOB index read
- Dominant language
- C++
- Stars
- 20.5k
- Forks
- 2.3k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 83
Description
`cgltf_validate` bounds-checks primitive index *values* against the vertex count, but for an `EXT_meshopt_compression` bufferView it validates the **fallback** buffer bytes, not the decoded stream. `cgltf_calc_index_bound` reads `buffer_view->buffer->data + offset` (fallback bytes), while the real indices live in a separate compressed stream decoded later.
Filament decodes it in `decodeMeshoptCompression` (`libs/gltfio/src/Utility.cpp:~90`), which sets `buffer_view->data = ` **after** validation:
```
ResourceLoader::loadResources:
loadCgltfBuffers(...) // cgltf_load_buffers + cgltf_validate (checks FALLBACK bytes)
decodeMeshoptCompression(...) // meshopt_decodeIndexBuffer -> real indices (NO re-validation)
```
So an attacker crafts a file whose fallback index region is valid (validation passes) but the meshopt-compressed stream decodes to indices `>= vertexCount`. After decode, `cgltf_accessor_read_index` returns OOB values that nothing re-checks. Confirmed at the cgltf/meshopt level with ASan.
**Impact:** OOB index read from an untrusted `.glb` on load.
**Suggested fix:** re-validate decoded meshopt index buffers against the vertex count after `decodeMeshoptCompression`. I previously opened PR #10175 with this fix; it was auto-closed (maintainer-only directory), so filing here as requested.
Contributor guide
Research direction
Start in libs/gltfio/src/Utility.cpp at decodeMeshoptCompression and trace its call from ResourceLoader::loadResources after loadCgltfBuffers and cgltf_validate. Re-validate decoded meshopt index buffers against the vertex count, then verify the reported malformed asset under ASan no longer produces an out-of-bounds index read.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- computer-graphics, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100