net: reject leading zeros in IP address parsers

In both net.ParseIP and net.ParseCIDR reject leading zeros in the
dot-decimal notation of IPv4 addresses.

Fixes #30999
Fixes #43389

Change-Id: I2b6a31fe84db89ac828cf5ed03eaa586ee96ab68
Reviewed-on: https://go-review.googlesource.com/c/go/+/325829
Trust: Roland Shoemaker <roland@golang.org>
Trust: Katie Hockman <katie@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Roland Shoemaker 2021-06-07 10:21:29 -07:00
parent da4a640141
commit d3e3d03666
5 changed files with 24 additions and 10 deletions

View file

@ -639,6 +639,16 @@ Do not send CLs removing the interior tags from such phrases.
<a href="/pkg/net/#ParseError"><code>ParseError</code></a> error type now implement <a href="/pkg/net/#ParseError"><code>ParseError</code></a> error type now implement
the <a href="/pkg/net/#Error"><code>net.Error</code></a> interface. the <a href="/pkg/net/#Error"><code>net.Error</code></a> interface.
</p> </p>
<p><!-- CL325829 -->
The <a href="/pkg/net/#ParseIP"><code>ParseIP</code></a> and <a href="/pkg/net/#ParseCIDR"><code>ParseCIDR</code></a>
functions now reject IPv4 addresses which contain decimal components with leading zeros.
These components were always interpreted as decimal, but some operating systems treat them as octal.
This mismatch could hypothetically lead to security issues if a Go application was used to validate IP addresses
which were then used in their original form with non-Go applications which interpreted components as octal. Generally,
it is advisable to always re-encoded values after validation, which avoids this class of parser misalignment issues.
</p>
</dd> </dd>
</dl><!-- net --> </dl><!-- net -->

View file

@ -36,7 +36,7 @@ var lookupStaticHostTests = []struct {
}, },
}, },
{ {
"testdata/ipv4-hosts", // see golang.org/issue/8996 "testdata/ipv4-hosts",
[]staticHostEntry{ []staticHostEntry{
{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}, {"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}},
{"localhost.localdomain", []string{"127.0.0.3"}}, {"localhost.localdomain", []string{"127.0.0.3"}},
@ -102,7 +102,7 @@ var lookupStaticAddrTests = []struct {
}, },
}, },
{ {
"testdata/ipv4-hosts", // see golang.org/issue/8996 "testdata/ipv4-hosts",
[]staticHostEntry{ []staticHostEntry{
{"127.0.0.1", []string{"localhost"}}, {"127.0.0.1", []string{"localhost"}},
{"127.0.0.2", []string{"localhost"}}, {"127.0.0.2", []string{"localhost"}},

View file

@ -574,6 +574,10 @@ func parseIPv4(s string) IP {
if !ok || n > 0xFF { if !ok || n > 0xFF {
return nil return nil
} }
if c > 1 && s[0] == '0' {
// Reject non-zero components with leading zeroes.
return nil
}
s = s[c:] s = s[c:]
p[i] = byte(n) p[i] = byte(n)
} }

View file

@ -21,9 +21,7 @@ var parseIPTests = []struct {
}{ }{
{"127.0.1.2", IPv4(127, 0, 1, 2)}, {"127.0.1.2", IPv4(127, 0, 1, 2)},
{"127.0.0.1", IPv4(127, 0, 0, 1)}, {"127.0.0.1", IPv4(127, 0, 0, 1)},
{"127.001.002.003", IPv4(127, 1, 2, 3)},
{"::ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, {"::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
{"::ffff:127.001.002.003", IPv4(127, 1, 2, 3)},
{"::ffff:7f01:0203", IPv4(127, 1, 2, 3)}, {"::ffff:7f01:0203", IPv4(127, 1, 2, 3)},
{"0:0:0:0:0000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, {"0:0:0:0:0000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
{"0:0:0:0:000000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, {"0:0:0:0:000000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
@ -43,6 +41,11 @@ var parseIPTests = []struct {
{"fe80::1%911", nil}, {"fe80::1%911", nil},
{"", nil}, {"", nil},
{"a1:a2:a3:a4::b1:b2:b3:b4", nil}, // Issue 6628 {"a1:a2:a3:a4::b1:b2:b3:b4", nil}, // Issue 6628
{"127.001.002.003", nil},
{"::ffff:127.001.002.003", nil},
{"123.000.000.000", nil},
{"1.2..4", nil},
{"0123.0.0.1", nil},
} }
func TestParseIP(t *testing.T) { func TestParseIP(t *testing.T) {
@ -358,6 +361,7 @@ var parseCIDRTests = []struct {
{"0.0.-2.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.-2.0/32"}}, {"0.0.-2.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.-2.0/32"}},
{"0.0.0.-3/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.-3/32"}}, {"0.0.0.-3/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.-3/32"}},
{"0.0.0.0/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.0/-0"}}, {"0.0.0.0/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.0/-0"}},
{"127.000.000.001/32", nil, nil, &ParseError{Type: "CIDR address", Text: "127.000.000.001/32"}},
{"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}}, {"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}},
} }

View file

@ -1,12 +1,8 @@
# See https://tools.ietf.org/html/rfc1123. # See https://tools.ietf.org/html/rfc1123.
#
# The literal IPv4 address parser in the net package is a relaxed
# one. It may accept a literal IPv4 address in dotted-decimal notation
# with leading zeros such as "001.2.003.4".
# internet address and host name # internet address and host name
127.0.0.1 localhost # inline comment separated by tab 127.0.0.1 localhost # inline comment separated by tab
127.000.000.002 localhost # inline comment separated by space 127.0.0.2 localhost # inline comment separated by space
# internet address, host name and aliases # internet address, host name and aliases
127.000.000.003 localhost localhost.localdomain 127.0.0.3 localhost localhost.localdomain