From bf9e54620fddd7adea334fdbf28e1973761df3bd Mon Sep 17 00:00:00 2001 From: DarthSim Date: Wed, 30 Aug 2023 14:36:33 +0400 Subject: [PATCH] Fix parsing of HEIF files with large boxes --- CHANGELOG.md | 2 ++ imagemeta/heif.go | 49 ++++++++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cf7c4ce..ed459596 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## [Unreleased] +### Fix +- Fix parsing of HEIF files with large boxes. ## [3.19.0] - 2023-08-21 ### Add diff --git a/imagemeta/heif.go b/imagemeta/heif.go index 049b68d3..e44cba44 100644 --- a/imagemeta/heif.go +++ b/imagemeta/heif.go @@ -6,11 +6,12 @@ import ( "errors" "fmt" "io" + "math" "github.com/imgproxy/imgproxy/v3/imagetype" ) -const heifBoxHeaderSize = int64(8) +const heifBoxHeaderSize = uint64(8) var heicBrand = []byte("heic") var avifBrand = []byte("avif") @@ -29,7 +30,7 @@ func (d *heifData) IsFilled() bool { return d.Format != imagetype.Unknown && d.Width > 0 && d.Height > 0 } -func heifReadN(r io.Reader, n int64) (b []byte, err error) { +func heifReadN(r io.Reader, n uint64) (b []byte, err error) { if buf, ok := r.(*bytes.Buffer); ok { b = buf.Next(int(n)) if len(b) == 0 { @@ -43,7 +44,7 @@ func heifReadN(r io.Reader, n int64) (b []byte, err error) { return } -func heifDiscardN(r io.Reader, n int64) error { +func heifDiscardN(r io.Reader, n uint64) error { if buf, ok := r.(*bytes.Buffer); ok { _ = buf.Next(int(n)) return nil @@ -54,11 +55,11 @@ func heifDiscardN(r io.Reader, n int64) error { return err } - _, err := io.CopyN(io.Discard, r, n) + _, err := io.CopyN(io.Discard, r, int64(n)) return err } -func heifReadBoxHeader(r io.Reader) (boxType string, boxDataSize int64, err error) { +func heifReadBoxHeader(r io.Reader) (boxType string, boxDataSize uint64, err error) { var b []byte b, err = heifReadN(r, heifBoxHeaderSize) @@ -66,9 +67,28 @@ func heifReadBoxHeader(r io.Reader) (boxType string, boxDataSize int64, err erro return } - boxDataSize = int64(binary.BigEndian.Uint32(b[0:4])) - heifBoxHeaderSize + headerSize := heifBoxHeaderSize + + boxDataSize = uint64(binary.BigEndian.Uint32(b[0:4])) boxType = string(b[4:8]) + if boxDataSize == 1 { + b, err = heifReadN(r, 8) + if err != nil { + return + } + + boxDataSize = (uint64(binary.BigEndian.Uint32(b[0:4])) << 32) | + uint64(binary.BigEndian.Uint32(b[4:8])) + headerSize += 8 + } + + if boxDataSize < heifBoxHeaderSize || boxDataSize > math.MaxInt64 { + return "", 0, errors.New("Invalid box data size") + } + + boxDataSize -= headerSize + return } @@ -86,7 +106,7 @@ func heifAssignFormat(d *heifData, brand []byte) bool { return false } -func heifReadFtyp(d *heifData, r io.Reader, boxDataSize int64) error { +func heifReadFtyp(d *heifData, r io.Reader, boxDataSize uint64) error { if boxDataSize < 8 { return errors.New("Invalid ftyp data") } @@ -101,7 +121,7 @@ func heifReadFtyp(d *heifData, r io.Reader, boxDataSize int64) error { } if boxDataSize >= 12 { - for i := int64(8); i < boxDataSize; i += 4 { + for i := uint64(8); i < boxDataSize; i += 4 { if heifAssignFormat(d, data[i:i+4]) { return nil } @@ -111,7 +131,7 @@ func heifReadFtyp(d *heifData, r io.Reader, boxDataSize int64) error { return errors.New("Image is not compatible with heic/avif") } -func heifReadMeta(d *heifData, r io.Reader, boxDataSize int64) error { +func heifReadMeta(d *heifData, r io.Reader, boxDataSize uint64) error { if boxDataSize < 4 { return errors.New("Invalid meta data") } @@ -130,7 +150,7 @@ func heifReadMeta(d *heifData, r io.Reader, boxDataSize int64) error { return nil } -func heifReadHldr(r io.Reader, boxDataSize int64) error { +func heifReadHldr(r io.Reader, boxDataSize uint64) error { if boxDataSize < 12 { return errors.New("Invalid hdlr data") } @@ -147,7 +167,7 @@ func heifReadHldr(r io.Reader, boxDataSize int64) error { return nil } -func heifReadIspe(r io.Reader, boxDataSize int64) (w, h int64, err error) { +func heifReadIspe(r io.Reader, boxDataSize uint64) (w, h int64, err error) { if boxDataSize < 12 { return 0, 0, errors.New("Invalid ispe data") } @@ -166,17 +186,10 @@ func heifReadIspe(r io.Reader, boxDataSize int64) (w, h int64, err error) { func heifReadBoxes(d *heifData, r io.Reader) error { for { boxType, boxDataSize, err := heifReadBoxHeader(r) - if err != nil { return err } - if boxDataSize < 0 { - return errors.New("Invalid box data") - } - - // log.Printf("Box type: %s; Box data size: %d", boxType, boxDataSize) - switch boxType { case "ftyp": if err := heifReadFtyp(d, r, boxDataSize); err != nil {