Skip to content

Commit

Permalink
Fix normalizeHeaderValue (#1963)
Browse files Browse the repository at this point in the history
The fuzzer found some cases where it would panic.

The output of normalizeHeaderValue doesn't need to affect s.b and s.hLen
because the length of the normalized header will never be bigger, so it
can just be normalize in place without affecting the rest of the buffer.
  • Loading branch information
erikdubbelboer authored Feb 22, 2025
1 parent 31e34c5 commit b8969ed
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 22 deletions.
11 changes: 11 additions & 0 deletions fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package fasthttp
import (
"bufio"
"bytes"
"encoding/base64"
"encoding/binary"
"net/url"
"strings"
"testing"
Expand Down Expand Up @@ -43,6 +45,15 @@ func FuzzVisitHeaderParams(f *testing.F) {

func FuzzResponseReadLimitBody(f *testing.F) {
f.Add([]byte("HTTP/1.1 200 OK\r\nContent-Type: aa\r\nContent-Length: 10\r\n\r\n9876543210"), 1024)
f.Add([]byte(" 0\nTrAnsfer-EnCoding:0\n\n0\r\n1:0\n 00\n 000\n\n"), 24922)
f.Add([]byte(" 0\n0:\n 0\n :\n"), 1048532)

// Case found by OSS-Fuzz.
b, err := base64.StdEncoding.DecodeString("oeYAdyAyClRyYW5zZmVyLUVuY29kaW5nOmlka7AKCjANCiA6MAogOgogOgogPgAAAAAAAAAgICAhICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiA6CiA6CiAgOgogOgogYDogCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogOgogOgogIDoKIDoKIGA6IAoKIDoKBSAgOgogOgogOgogOgogIDoKIDoKIGA6IAAgIAA6CiA6CiA6CjoKIDoKIDoWCiAyIOgKIDogugogOjAKIDoKIDoKBSAgOgogOgogOgogOgogIDoKIDoKIGA6IAAgIAAAAAAAAABaYQ==")
if err != nil {
panic(err)
}
f.Add(b[:len(b)-2], int(binary.LittleEndian.Uint16(b[len(b)-2:])))

f.Fuzz(func(t *testing.T, body []byte, maxBodySize int) {
if len(body) > 1024*1024 || maxBodySize > 1024*1024 {
Expand Down
26 changes: 4 additions & 22 deletions header.go
Original file line number Diff line number Diff line change
Expand Up @@ -3331,7 +3331,6 @@ func (s *headerScanner) next() bool {
s.err = errNeedMore
return false
}
isMultiLineValue := false
for {
if n+1 >= len(s.b) {
break
Expand All @@ -3351,14 +3350,12 @@ func (s *headerScanner) next() bool {
s.nextNewLine = d - c - 1
break
}
isMultiLineValue = true
n = e
}
if n >= len(s.b) {
s.err = errNeedMore
return false
}
oldB := s.b
s.value = s.b[:n]
s.hLen += n + 1
s.b = s.b[n+1:]
Expand All @@ -3370,8 +3367,8 @@ func (s *headerScanner) next() bool {
n--
}
s.value = s.value[:n]
if isMultiLineValue {
s.value, s.b, s.hLen = normalizeHeaderValue(s.value, oldB, s.hLen)
if bytes.Contains(s.b, strCRLF) {
s.value = normalizeHeaderValue(s.value)
}

return true
Expand Down Expand Up @@ -3445,7 +3442,7 @@ func getHeaderKeyBytes(bufK []byte, key string, disableNormalizing bool) []byte
return bufK
}

func normalizeHeaderValue(ov, ob []byte, headerLength int) (nv, nb []byte, nhl int) {
func normalizeHeaderValue(ov []byte) (nv []byte) {
nv = ov
length := len(ov)
if length <= 0 {
Expand Down Expand Up @@ -3480,23 +3477,8 @@ func normalizeHeaderValue(ov, ob []byte, headerLength int) (nv, nb []byte, nhl i
write++
}

nv = nv[:write]
copy(ob[write:], ob[write+shrunk:])
nv = nv[:length-shrunk]

// Check if we need to skip \r\n or just \n
skip := 0
if ob[write] == rChar {
if ob[write+1] == nChar {
skip += 2
} else {
skip++
}
} else if ob[write] == nChar {
skip++
}

nb = ob[write+skip : len(ob)-shrunk]
nhl = headerLength - shrunk
return
}

Expand Down

0 comments on commit b8969ed

Please sign in to comment.