diff options
author | Filippo Valsorda <filippo@golang.org> | 2021-05-10 19:32:13 +0200 |
---|---|---|
committer | Filippo Valsorda <filippo@golang.org> | 2021-05-11 18:22:54 +0000 |
commit | 9b84814f6e909bfe9054eab30e423bc5e880d137 (patch) | |
tree | 91014126f96e867812f1dc270018e32f10f42bf4 /src/net | |
parent | 2520e72d3bbfe6651cd6324077afdb4babb36b9a (diff) | |
download | go-9b84814f6e909bfe9054eab30e423bc5e880d137.tar.gz go-9b84814f6e909bfe9054eab30e423bc5e880d137.zip |
net/http: check that Unicode-aware functions are not used
Change-Id: I398aff06bec95077bfff02bfb067aa949b70c184
Reviewed-on: https://go-review.googlesource.com/c/go/+/318429
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Roberto Clapis <roberto@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
Diffstat (limited to 'src/net')
-rw-r--r-- | src/net/http/http_test.go | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go index 3f1d7cee71..0d92fe5f96 100644 --- a/src/net/http/http_test.go +++ b/src/net/http/http_test.go @@ -9,9 +9,13 @@ package http import ( "bytes" "internal/testenv" + "io/fs" "net/url" + "os" "os/exec" "reflect" + "regexp" + "strings" "testing" ) @@ -156,3 +160,61 @@ func BenchmarkCopyValues(b *testing.B) { b.Fatal("Benchmark wasn't run") } } + +var forbiddenStringsFunctions = map[string]bool{ + // Functions that use Unicode-aware case folding. + "EqualFold": true, + "Title": true, + "ToLower": true, + "ToLowerSpecial": true, + "ToTitle": true, + "ToTitleSpecial": true, + "ToUpper": true, + "ToUpperSpecial": true, + + // Functions that use Unicode-aware spaces. + "Fields": true, + "TrimSpace": true, +} + +// TestNoUnicodeStrings checks that nothing in net/http uses the Unicode-aware +// strings and bytes package functions. HTTP is mostly ASCII based, and doing +// Unicode-aware case folding or space stripping can introduce vulnerabilities. +func TestNoUnicodeStrings(t *testing.T) { + if !testenv.HasSrc() { + t.Skip("source code not available") + } + + re := regexp.MustCompile(`(strings|bytes).([A-Za-z]+)`) + if err := fs.WalkDir(os.DirFS("."), ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + t.Fatal(err) + } + + if path == "internal/ascii" { + return fs.SkipDir + } + if !strings.HasSuffix(path, ".go") || + strings.HasSuffix(path, "_test.go") || + path == "h2_bundle.go" || d.IsDir() { + return nil + } + + contents, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + for lineNum, line := range strings.Split(string(contents), "\n") { + for _, match := range re.FindAllStringSubmatch(line, -1) { + if !forbiddenStringsFunctions[match[2]] { + continue + } + t.Errorf("disallowed call to %s at %s:%d", match[0], path, lineNum+1) + } + } + + return nil + }); err != nil { + t.Fatal(err) + } +} |