From: Grégoire Lodi Date: Wed, 5 Mar 2025 09:44:46 +0000 (+0000) Subject: net/http: make http.FileServer return 404 when a path is invalid/unsafe X-Git-Tag: go1.25rc1~826 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=061efaa8a761458eaa41119ffd59033738cf141c;p=gostls13.git net/http: make http.FileServer return 404 when a path is invalid/unsafe This PR adds error handling in net/http toHTTPError to return a 404 instead of a 500 when net/http fs.Dir.Open throws the error http: invalid or unsafe file path. Fixes #72091 Change-Id: I7941c8fca5160a4a82732dc1d05b9b95eac84fbf GitHub-Last-Rev: 04b5019dfb629820621f3776d6f22fd754171565 GitHub-Pull-Request: golang/go#72108 Reviewed-on: https://go-review.googlesource.com/c/go/+/654975 Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil Reviewed-by: Damien Neil --- diff --git a/src/net/http/fs.go b/src/net/http/fs.go index 48ba05a664..92bd94f72d 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -67,6 +67,11 @@ func mapOpenError(originalErr error, name string, sep rune, stat func(string) (f return originalErr } +// errInvalidUnsafePath is returned by Dir.Open when the call to +// filepath.Localize fails. filepath.Localize returns an error if the path +// cannot be represented by the operating system. +var errInvalidUnsafePath = errors.New("http: invalid or unsafe file path") + // Open implements [FileSystem] using [os.Open], opening files for reading rooted // and relative to the directory d. func (d Dir) Open(name string) (File, error) { @@ -76,7 +81,7 @@ func (d Dir) Open(name string) (File, error) { } path, err := filepath.Localize(path) if err != nil { - return nil, errors.New("http: invalid or unsafe file path") + return nil, errInvalidUnsafePath } dir := string(d) if dir == "" { @@ -768,6 +773,9 @@ func toHTTPError(err error) (msg string, httpStatus int) { if errors.Is(err, fs.ErrPermission) { return "403 Forbidden", StatusForbidden } + if errors.Is(err, errInvalidUnsafePath) { + return "404 page not found", StatusNotFound + } // Default: return "500 Internal Server Error", StatusInternalServerError } diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go index 3149ca35ac..9b34ad080e 100644 --- a/src/net/http/fs_test.go +++ b/src/net/http/fs_test.go @@ -733,6 +733,27 @@ func testFileServerZeroByte(t *testing.T, mode testMode) { } } +func TestFileServerNullByte(t *testing.T) { run(t, testFileServerNullByte) } +func testFileServerNullByte(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts + + for _, path := range []string{ + "/file%00", + "/%00", + "/file/qwe/%00", + } { + res, err := ts.Client().Get(ts.URL + path) + if err != nil { + t.Fatal(err) + } + res.Body.Close() + if res.StatusCode != 404 { + t.Errorf("Get(%q): got status %v, want 404", path, res.StatusCode) + } + + } +} + func TestFileServerNamesEscape(t *testing.T) { run(t, testFileServerNamesEscape) } func testFileServerNamesEscape(t *testing.T, mode testMode) { ts := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts