From eb767ab15f0ee3d7638dfbda2bd073e418bf2809 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Thu, 8 Jun 2017 20:40:12 +0200 Subject: [PATCH 1/2] pack: Handle small files --- src/restic/pack/pack.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/restic/pack/pack.go b/src/restic/pack/pack.go index 6666d886a..67d8fba82 100644 --- a/src/restic/pack/pack.go +++ b/src/restic/pack/pack.go @@ -189,9 +189,26 @@ func readHeaderLength(rd io.ReaderAt, size int64) (uint32, error) { const maxHeaderSize = 16 * 1024 * 1024 +// we require at least one entry in the header, and one blob for a pack file +var minFileSize = entrySize + crypto.Extension + // readHeader reads the header at the end of rd. size is the length of the // whole data accessible in rd. func readHeader(rd io.ReaderAt, size int64) ([]byte, error) { + if size == 0 { + err := InvalidFileError{ + Message: "file is empty", + } + return nil, errors.Wrap(err, "readHeader") + } + + if size < int64(minFileSize) { + err := InvalidFileError{ + Message: "file is too small", + } + return nil, errors.Wrap(err, "readHeader") + } + hl, err := readHeaderLength(rd, size) if err != nil { return nil, err @@ -218,6 +235,15 @@ func readHeader(rd io.ReaderAt, size int64) ([]byte, error) { return buf, nil } +// InvalidFileError is return when a file is found that is not a pack file. +type InvalidFileError struct { + Message string +} + +func (e InvalidFileError) Error() string { + return e.Message +} + // List returns the list of entries found in a pack file. func List(k *crypto.Key, rd io.ReaderAt, size int64) (entries []restic.Blob, err error) { buf, err := readHeader(rd, size) From 48fecd791de16a761793bdd2c7568fcc00770411 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Thu, 8 Jun 2017 21:04:07 +0200 Subject: [PATCH 2/2] pack: Handle more invalid header cases --- src/restic/pack/pack.go | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/restic/pack/pack.go b/src/restic/pack/pack.go index 67d8fba82..a7965f97a 100644 --- a/src/restic/pack/pack.go +++ b/src/restic/pack/pack.go @@ -8,6 +8,7 @@ import ( "restic" "sync" + "restic/debug" "restic/errors" "restic/crypto" @@ -195,17 +196,14 @@ var minFileSize = entrySize + crypto.Extension // readHeader reads the header at the end of rd. size is the length of the // whole data accessible in rd. func readHeader(rd io.ReaderAt, size int64) ([]byte, error) { + debug.Log("size: %v", size) if size == 0 { - err := InvalidFileError{ - Message: "file is empty", - } + err := InvalidFileError{Message: "file is empty"} return nil, errors.Wrap(err, "readHeader") } if size < int64(minFileSize) { - err := InvalidFileError{ - Message: "file is too small", - } + err := InvalidFileError{Message: "file is too small"} return nil, errors.Wrap(err, "readHeader") } @@ -214,6 +212,23 @@ func readHeader(rd io.ReaderAt, size int64) ([]byte, error) { return nil, err } + debug.Log("header length: %v", size) + + if hl == 0 { + err := InvalidFileError{Message: "header length is zero"} + return nil, errors.Wrap(err, "readHeader") + } + + if hl < crypto.Extension { + err := InvalidFileError{Message: "header length is too small"} + return nil, errors.Wrap(err, "readHeader") + } + + if (hl-crypto.Extension)%uint32(entrySize) != 0 { + err := InvalidFileError{Message: "header length is invalid"} + return nil, errors.Wrap(err, "readHeader") + } + if int64(hl) > size-int64(binary.Size(hl)) { return nil, errors.New("header is larger than file") }