Skip to content

Commit

Permalink
internal/zstd: avoid panic when windowSize is negative
Browse files Browse the repository at this point in the history
Consistency of Window_Size and Frame_Content_Size value ranges as
per RFC 8878 3.1.1.1.2 to resolve panic issues.

Fixes golang#63979
  • Loading branch information
aimuz committed Nov 7, 2023
1 parent 9d836d4 commit 2f398d4
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/internal/zstd/fuzz_test.go
Expand Up @@ -22,6 +22,7 @@ var badStrings = []string{
"(\xb5/\xfd\x1002000$\x05\x0010\xcc0\xa8100000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"(\xb5/\xfd\x1002000$\x05\x0000\xcc0\xa8100d\x0000001000000000000000000000000000000000000000000000000000000000000000000000000\x000000000000000000000000000000000000000000000000000000000000000000000000000000",
"(\xb5/\xfd001\x00\x0000000000000000000",
"(\xb5/\xfd\xe40000000\xfa20\x000",
}

// This is a simple fuzzer to see if the decompressor panics.
Expand Down
12 changes: 6 additions & 6 deletions src/internal/zstd/window.go
Expand Up @@ -12,13 +12,13 @@ package zstd
// and update off such that it always points at
// the byte stored before others.
type window struct {
size int
size uint64
data []byte
off int
}

// reset clears stored data and configures window size.
func (w *window) reset(size int) {
func (w *window) reset(size uint64) {
w.data = w.data[:0]
w.off = 0
w.size = size
Expand All @@ -38,15 +38,15 @@ func (w *window) save(buf []byte) {
return
}

if len(buf) >= w.size {
from := len(buf) - w.size
if uint64(len(buf)) >= w.size {
from := uint64(len(buf)) - w.size
w.data = append(w.data[:0], buf[from:]...)
w.off = 0
return
}

// Update off to point to the oldest remaining byte.
free := w.size - len(w.data)
free := w.size - uint64(len(w.data))
if free == 0 {
n := copy(w.data[w.off:], buf)
if n == len(buf) {
Expand All @@ -55,7 +55,7 @@ func (w *window) save(buf []byte) {
w.off = copy(w.data, buf[n:])
}
} else {
if free >= len(buf) {
if free >= uint64(len(buf)) {
w.data = append(w.data, buf...)
} else {
w.data = append(w.data, buf[:free]...)
Expand Down
2 changes: 1 addition & 1 deletion src/internal/zstd/window_test.go
Expand Up @@ -39,7 +39,7 @@ func TestWindow(t *testing.T) {
// Third sequence tests read offset that can become non-zero only after second save.
func testWindow(t *testing.T, size int, a, b, c []byte) {
var w window
w.reset(size)
w.reset(uint64(size))

w.save(a)
w.save(b)
Expand Down
9 changes: 5 additions & 4 deletions src/internal/zstd/zstd.go
Expand Up @@ -237,7 +237,7 @@ retry:

// Figure out the maximum amount of data we need to retain
// for backreferences.
var windowSize int
var windowSize uint64
if !singleSegment {
// Window descriptor. RFC 3.1.1.1.2.
windowDescriptor := r.scratch[0]
Expand All @@ -246,7 +246,7 @@ retry:
windowLog := exponent + 10
windowBase := uint64(1) << windowLog
windowAdd := (windowBase / 8) * mantissa
windowSize = int(windowBase + windowAdd)
windowSize = windowBase + windowAdd

// Default zstd sets limits on the window size.
if fuzzing && (windowLog > 31 || windowSize > 1<<27) {
Expand Down Expand Up @@ -287,8 +287,9 @@ retry:
// RFC 3.1.1.1.2.
// When Single_Segment_Flag is set, Window_Descriptor is not present.
// In this case, Window_Size is Frame_Content_Size.
// can be any value from 1 to 2^64-1 bytes (16 EB).
if singleSegment {
windowSize = int(r.remainingFrameSize)
windowSize = r.remainingFrameSize
}

// RFC 8878 3.1.1.1.1.2. permits us to set an 8M max on window size.
Expand Down Expand Up @@ -382,7 +383,7 @@ func (r *Reader) readBlock() error {
// Maximum block size is smaller of window size and 128K.
// We don't record the window size for a single segment frame,
// so just use 128K. RFC 3.1.1.2.3, 3.1.1.2.4.
if blockSize > 128<<10 || (r.window.size > 0 && blockSize > r.window.size) {
if blockSize > 128<<10 || (r.window.size > 0 && uint64(blockSize) > r.window.size) {
return r.makeError(relativeOffset, "block size too large")
}

Expand Down

0 comments on commit 2f398d4

Please sign in to comment.