Skip to content

readPictureBlock: unbounded allocation from attacker-controlled length field #116

Description

@bararchy

Bug

readPictureBlock in vorbis.go reads a 4-byte dataLen from the input and passes it directly to make([]byte, dataLen) without any size cap:

// vorbis.go, line ~132
dataLen, err := readInt(r, 4)
if err != nil {
    return err
}
data := make([]byte, dataLen)

A crafted FLAC file with dataLen = 0x7FFFFFFF causes a ~2 GB allocation from a 49-byte input. The allocation happens before io.ReadFull returns EOF, so the memory is committed regardless.

The rest of the codebase already has readBytesMaxUpfront (10 MB cap) in readBytes() / readString(), but this code path uses a raw make instead.

Reproduction

49-byte FLAC file (base64):

ZkxhQ4YAACkAAAADAAAACWltYWdlL3BuZwAAAAAAAAAAAAAAAAAAAAAAAAAAf////w==

Decode and run:

echo 'ZkxhQ4YAACkAAAADAAAACWltYWdlL3BuZwAAAAAAAAAAAAAAAAAAAAAAAAAAf////w==' | base64 -d > poc.bin
# Then in Go:
# tag.ReadFrom(bytes.NewReader(pocBytes))
# Observe ~2 GB allocation via runtime.ReadMemStats

Measured: TotalAlloc delta = 2147520480 bytes (2147.5 MB) from a 49-byte file. Tested on current HEAD (3d75831).

SHA-256 of poc.bin: 3ba94bb0597fa4689cad34e8f1e9866901cad38a64e80ab196504696322b88f8

Suggested fix

Cap dataLen the same way readString / readBytes already do, or just reuse readBytes:

data, err := readBytes(r, uint(dataLen))

This would apply the existing readBytesMaxUpfront guard.

Impact

Any Go service that calls tag.ReadFrom() on untrusted audio files (media uploads, metadata extraction) can be forced into a multi-GB allocation by a small crafted FLAC file.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions