Skip to content

fix: validate ClusterBits and BlocksInImage; fix uint32 overflow in getGDGT#2001

Open
GusFromSpace wants to merge 1 commit intogoogle:mainfrom
GusFromSpace:fix/vm-parser-integer-overflow
Open

fix: validate ClusterBits and BlocksInImage; fix uint32 overflow in getGDGT#2001
GusFromSpace wants to merge 1 commit intogoogle:mainfrom
GusFromSpace:fix/vm-parser-integer-overflow

Conversation

@GusFromSpace
Copy link
Copy Markdown

Summary

Fixes three Denial-of-Service vulnerabilities in the embedded filesystem extractors for QCOW2, VMDK, and VDI disk image formats. All three are triggered by parsing a maliciously crafted disk image file passed to OSV-SCALIBR.

These were identified and confirmed with working PoC tests by Mesopredator, an autonomous security analysis system. A security report was submitted to Google VRP on 2026-04-23.


QCOW2 — Unbounded ClusterBits allocation → runtime panic

File: extractor/filesystem/embeddedfs/qcow2/format.go
Functions: readL1Table, readL2Table

header.ClusterBits is read from the image with no bounds check. The QCOW2 spec permits values 9–21 only. With ClusterBits=62, uint64(1) << 62 produces a 4-exabyte value passed to make([]byte, ...), which panics the Go runtime immediately.

Fix: Validate ClusterBits in range 9–21 at the entry of both functions.


VMDK — uint32 overflow bypasses size check in getGDGT

File: extractor/filesystem/embeddedfs/vmdk/vmdk.go
Function: getGDGT

GTsectors*GTs is uint32 multiplication. It overflows before being cast to int64, so the totalBytes > 1<<31 bounds check operates on a wrapped value and silently passes. The gdarr allocation overflows for the same reason, producing a zero-length slice. Any subsequent indexed access panics.

Fix: Cast each operand to int64 before multiplication.


VDI — Unbounded BlocksInImage allocation → forced multi-GB allocation

File: extractor/filesystem/embeddedfs/vdi/vdi.go
Function: convertVDIToRaw

hdr.BlocksInImage is a uint32 read directly from the image header with no upper bound. make([]uint32, 0x3FFFFFFF) allocates ~4 GB. On memory-constrained hosts or with the maximum uint32 value, the process crashes.

Fix: Reject images where BlocksInImage > 2*1024*1024 (2M blocks — well above any real VDI image).


Test plan

  • go test ./extractor/filesystem/embeddedfs/qcow2/... — passes
  • go test ./extractor/filesystem/embeddedfs/vmdk/... — passes
  • go test ./extractor/filesystem/embeddedfs/vdi/... — passes
  • PoC inputs confirmed to trigger errors rather than panics/OOM after fix

Identified by Mesopredator autonomous security analysis.

…etGDGT

Three DoS vulnerabilities in VM disk image parsers, all triggered by
parsing a maliciously crafted disk image file.

QCOW2 (format.go): ClusterBits is read from the image header with no
bounds check. The QCOW2 spec limits valid values to 9-21. Without this
check, ClusterBits=62 causes make([]byte, 4EB) which panics the runtime.
Validation added to both readL1Table and readL2Table.

VMDK (vmdk.go): GDsectors, GTsectors, and GTs are uint32 values.
Multiplying them before widening to int64 causes overflow, producing a
wrapped totalSectors that bypasses the >1<<31 size check. The gdarr
allocation overflows for the same reason. Fixed by casting each operand
to int64 before multiplication.

VDI (vdi.go): BlocksInImage is a uint32 read directly from the image
header with no upper bound. make([]uint32, 0x3FFFFFFF) allocates ~4GB.
Added a 2M-block cap (2*1024*1024), generous for any real VDI image.
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Apr 24, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant