From c5214f30be8853d5dd898cace25288efabbfeb6e Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Wed, 10 Dec 2025 17:41:25 +0800 Subject: [PATCH] fix: prevent panic on malformed ISO9660 path table Add bounds checking in parsePathTable to prevent slice bounds out of range panic when parsing malformed ISO9660 images with truncated path table entries. Found by fuzzing: the path table entry's dirNameLen field could specify a length exceeding the remaining buffer, causing a panic when slicing. --- iso9660/iso9660.go | 9 +++++---- iso9660/iso9660_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/iso9660/iso9660.go b/iso9660/iso9660.go index ed1da63..995021e 100644 --- a/iso9660/iso9660.go +++ b/iso9660/iso9660.go @@ -198,15 +198,16 @@ func (iso *ISO9660) parsePathTable() error { iso.pathTable = nil i := 0 for i < len(pathTableRaw) { - if i >= len(pathTableRaw) { - break - } - dirNameLen := int(pathTableRaw[i]) if dirNameLen == 0 { break } + // Validate we have enough data for this entry (8 byte header + name) + if i+8+dirNameLen > len(pathTableRaw) { + return fmt.Errorf("truncated path table entry at offset %d", i) + } + // Extended attribute record length at i+1 (skip) dirLBA := binary.LittleEndian.Uint32(pathTableRaw[i+2 : i+6]) dirParentIdx := int(binary.LittleEndian.Uint16(pathTableRaw[i+6:i+8])) - 1 diff --git a/iso9660/iso9660_test.go b/iso9660/iso9660_test.go index aaf1a71..f0ffe52 100644 --- a/iso9660/iso9660_test.go +++ b/iso9660/iso9660_test.go @@ -545,3 +545,40 @@ func TestGetDataPreparerID(t *testing.T) { // Data preparer ID is at a different offset - our minimal ISO doesn't set it _ = iso.GetDataPreparerID() } + +// TestISO9660_TruncatedPathTable verifies bounds check for malformed path table entries. +func TestISO9660_TruncatedPathTable(t *testing.T) { + t.Parallel() + + tmpDir := t.TempDir() + + // Create a minimal ISO + isoData := createMinimalISO("VOL", "SYS", "PUB") + + // Corrupt the path table: set a directory name length that exceeds the path table size + // Path table is at block 18 (offset 18 * 2048 = 36864) + pathTableOffset := 18 * 2048 + + // Set directory name length to a large value (e.g., 100) that exceeds remaining data + // The path table entry format is: + // - byte 0: directory name length + // - byte 1: extended attribute record length + // - bytes 2-5: directory LBA (little-endian) + // - bytes 6-7: parent directory number (little-endian) + // - bytes 8+: directory name + isoData[pathTableOffset] = 100 // Large name length that would overflow + + isoPath := filepath.Join(tmpDir, "truncated.iso") + if err := os.WriteFile(isoPath, isoData, 0o600); err != nil { + t.Fatalf("Failed to write ISO: %v", err) + } + + // This should fail with a truncated path table error, not panic + _, err := Open(isoPath) + if err == nil { + t.Error("Open() should error for truncated path table entry") + } + if !strings.Contains(err.Error(), "truncated path table entry") { + t.Errorf("Open() error = %v, want error containing 'truncated path table entry'", err) + } +}