bf9395e022
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
86 lines
3.6 KiB
Go
86 lines
3.6 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package im
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"testing"
|
|
)
|
|
|
|
// build64BitBox builds an ISO-BMFF box using the 64-bit "largesize" form: the
|
|
// 32-bit size field is set to 1 and an 8-byte largesize follows the 4-byte box
|
|
// type. largesize is the total box length including the 16-byte header.
|
|
func build64BitBox(boxType string, largesize uint64, payload []byte) []byte {
|
|
box := make([]byte, 16+len(payload))
|
|
binary.BigEndian.PutUint32(box[0:4], 1) // size == 1 → 64-bit largesize follows
|
|
copy(box[4:8], boxType)
|
|
binary.BigEndian.PutUint64(box[8:16], largesize)
|
|
copy(box[16:], payload)
|
|
return box
|
|
}
|
|
|
|
// build32BitBox builds an ISO-BMFF box using the ordinary 32-bit size form.
|
|
func build32BitBox(boxType string, payload []byte) []byte {
|
|
box := make([]byte, 8+len(payload))
|
|
binary.BigEndian.PutUint32(box[0:4], uint32(len(box)))
|
|
copy(box[4:8], boxType)
|
|
copy(box[8:], payload)
|
|
return box
|
|
}
|
|
|
|
// TestMP4BoxLargeSizeOverflowNoPanic guards the 64-bit box-size branch against
|
|
// CWE-190 integer overflow. A largesize whose high bit is set converts to a
|
|
// negative offset; without a bounds guard that offset indexes the input slice
|
|
// out of range and panics, crashing the CLI on a crafted/corrupt MP4 (the
|
|
// in-memory walkers run on URL-sourced media that the caller does not control).
|
|
// The walkers' contract is best-effort: malformed input must return 0, not panic.
|
|
func TestMP4BoxLargeSizeOverflowNoPanic(t *testing.T) {
|
|
// A single top-level box in the 64-bit form with largesize = 2^64-1.
|
|
data := build64BitBox("ftyp", 0xFFFFFFFFFFFFFFFF, nil)
|
|
|
|
if got := readMp4DurationBytes(data); got != 0 {
|
|
t.Errorf("readMp4DurationBytes(overflow largesize) = %d, want 0", got)
|
|
}
|
|
if got := parseMp4Duration(data); got != 0 {
|
|
t.Errorf("parseMp4Duration(overflow largesize) = %d, want 0", got)
|
|
}
|
|
if start, end := findMP4Box(data, 0, len(data), "ftyp"); start != -1 || end != -1 {
|
|
t.Errorf("findMP4Box(overflow largesize) = (%d, %d), want (-1, -1)", start, end)
|
|
}
|
|
}
|
|
|
|
// TestMP4Box64BitSizeAtNonZeroOffset locks in correct handling of a 64-bit box
|
|
// that does not start at offset 0. boxEnd must be offset+largesize (as the
|
|
// 32-bit branch already does with offset+size); dropping the offset truncates
|
|
// the box and the duration is silently lost.
|
|
func TestMP4Box64BitSizeAtNonZeroOffset(t *testing.T) {
|
|
mvhd := buildMvhdBox(0, 1000, 5000) // timescale=1000, duration=5000 → 5000ms
|
|
// moov carried as a 64-bit box: largesize = 16-byte header + mvhd payload.
|
|
moov := build64BitBox("moov", uint64(16+len(mvhd)), mvhd)
|
|
// Precede moov with a 32-bit ftyp box so it sits at a non-zero offset —
|
|
// that is where the missing "offset +" surfaces.
|
|
data := append(build32BitBox("ftyp", []byte("isom")), moov...)
|
|
|
|
if got := readMp4DurationBytes(data); got != 5000 {
|
|
t.Errorf("readMp4DurationBytes(64-bit moov at offset>0) = %d, want 5000", got)
|
|
}
|
|
}
|
|
|
|
// TestFindMP4Box64BitSizeAtNonZeroOffset is the findMP4Box-level analogue: a
|
|
// 64-bit box preceding the target must advance the cursor by offset+largesize
|
|
// so the following box is located at the right position.
|
|
func TestFindMP4Box64BitSizeAtNonZeroOffset(t *testing.T) {
|
|
free := build64BitBox("free", 24, make([]byte, 8)) // 16-byte header + 8 bytes
|
|
target := build32BitBox("mvhd", []byte("payload!"))
|
|
data := append(free, target...)
|
|
|
|
start, end := findMP4Box(data, 0, len(data), "mvhd")
|
|
if start < 0 {
|
|
t.Fatalf("findMP4Box did not find mvhd after a 64-bit box (start=%d)", start)
|
|
}
|
|
if got := string(data[start:end]); got != "payload!" {
|
|
t.Errorf("findMP4Box returned %q, want %q", got, "payload!")
|
|
}
|
|
}
|