Fix Rdlength related parsing bug in RFC3597 records (#1214)

* Set Rdlength in fromRFC3597

This was a bug found by oss-fuzz. My bad (#1211).

* Limit maximum length of Rdata in (*RFC3597).parse

RDATA must be a 16-bit unsigned integer.

* Validate Rdlength and off in UnpackRRWithHeader

* Revert "Validate Rdlength and off in UnpackRRWithHeader"

This reverts commit 2f6a8811b944b100af7605e53a6fb164944a6d65.

* Use hex.DecodedLen in (*RFC3597).fromRFC3597

While this isn't done elsewhere, it is clearer and more obvious.
This commit is contained in:
Tom Thorogood 2021-02-01 18:40:38 +10:30 committed by GitHub
parent ba2d042a57
commit e6df8867af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 26 additions and 6 deletions

9
dns.go
View File

@ -134,9 +134,14 @@ func (rr *RFC3597) ToRFC3597(r RR) error {
// fromRFC3597 converts an unknown RR representation from RFC 3597 to the known RR type.
func (rr *RFC3597) fromRFC3597(r RR) error {
*r.Header() = rr.Hdr
hdr := r.Header()
*hdr = rr.Hdr
if len(rr.Rdata) == 0 {
// Can't overflow uint16 as the length of Rdata is validated in (*RFC3597).parse.
// We can only get here when rr was constructed with that method.
hdr.Rdlength = uint16(hex.DecodedLen(len(rr.Rdata)))
if noRdata(*hdr) {
// Dynamic update.
return nil
}

View File

@ -1387,7 +1387,7 @@ func (rr *RFC3597) parse(c *zlexer, o string) *ParseError {
c.Next() // zBlank
l, _ = c.Next()
rdlength, e := strconv.Atoi(l.token)
rdlength, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{"", "bad RFC3597 Rdata ", l}
}
@ -1396,7 +1396,7 @@ func (rr *RFC3597) parse(c *zlexer, o string) *ParseError {
if e1 != nil {
return e1
}
if rdlength*2 != len(s) {
if int(rdlength)*2 != len(s) {
return &ParseError{"", "bad RFC3597 Rdata", l}
}
rr.Rdata = s

View File

@ -229,8 +229,23 @@ example.com. 60 PX (
}
}
func TestParseRFC3597InvalidLength(t *testing.T) {
// We need to space separate the 00s otherwise it will exceed the maximum token size
// of the zone lexer.
_, err := NewRR("example. 3600 CLASS1 TYPE1 \\# 65536 " + strings.Repeat("00 ", 65536))
if err == nil {
t.Error("should not have parsed excessively long RFC3579 record")
}
}
func TestParseKnownRRAsRFC3597(t *testing.T) {
t.Run("with RDATA", func(t *testing.T) {
// This was found by oss-fuzz.
_, err := NewRR("example. 3600 tYpe44 \\# 03 75 0100")
if err != nil {
t.Errorf("failed to parse RFC3579 format: %v", err)
}
rr, err := NewRR("example. 3600 CLASS1 TYPE1 \\# 4 7f000001")
if err != nil {
t.Fatalf("failed to parse RFC3579 format: %v", err)
@ -247,7 +262,7 @@ func TestParseKnownRRAsRFC3597(t *testing.T) {
localhost := net.IPv4(127, 0, 0, 1)
if !a.A.Equal(localhost) {
t.Fatalf("expected A with IP %v, but got %v", localhost, a.A)
t.Errorf("expected A with IP %v, but got %v", localhost, a.A)
}
})
t.Run("without RDATA", func(t *testing.T) {
@ -266,7 +281,7 @@ func TestParseKnownRRAsRFC3597(t *testing.T) {
}
if len(a.A) != 0 {
t.Fatalf("expected A with empty IP, but got %v", a.A)
t.Errorf("expected A with empty IP, but got %v", a.A)
}
})
}