diff --git a/pkg/routes/logs.go b/pkg/routes/logs.go index ef9cd4ef616..8cda4132a5f 100644 --- a/pkg/routes/logs.go +++ b/pkg/routes/logs.go @@ -18,7 +18,9 @@ package routes import ( "net/http" + "os" "path" + "syscall" "github.com/emicklei/go-restful" ) @@ -42,6 +44,12 @@ func (l Logs) Install(c *restful.Container) { func logFileHandler(req *restful.Request, resp *restful.Response) { logdir := "/var/log" actual := path.Join(logdir, req.PathParameter("logpath")) + + // check filename length first, return 404 if it's oversize. + if logFileNameIsTooLong(actual) { + http.Error(resp, "file not found", http.StatusNotFound) + return + } http.ServeFile(resp.ResponseWriter, req.Request, actual) } @@ -49,3 +57,15 @@ func logFileListHandler(req *restful.Request, resp *restful.Response) { logdir := "/var/log" http.ServeFile(resp.ResponseWriter, req.Request, logdir) } + +// logFileNameIsTooLong checks filename length, returns true if it's longer than 255. +// cause http.ServeFile returns default error code 500 except for NotExist and Forbidden, but we need to separate the real 500 from oversize filename here. +func logFileNameIsTooLong(filePath string) bool { + _, err := os.Stat(filePath) + if err != nil { + if e, ok := err.(*os.PathError); ok && e.Err == syscall.ENAMETOOLONG { + return true + } + } + return false +} diff --git a/pkg/routes/logs_test.go b/pkg/routes/logs_test.go new file mode 100644 index 00000000000..0b2ede3023a --- /dev/null +++ b/pkg/routes/logs_test.go @@ -0,0 +1,48 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package routes + +import ( + "fmt" + "os" + "testing" +) + +func TestPreCheckLogFileNameLength(t *testing.T) { + oversizeFileName := fmt.Sprintf("%0256s", "a") + normalFileName := fmt.Sprintf("%0255s", "a") + + // check file with oversize name. + if !logFileNameIsTooLong(oversizeFileName) { + t.Error("failed to check oversize filename") + } + + // check file with normal name which doesn't exist. + if logFileNameIsTooLong(normalFileName) { + t.Error("failed to check normal filename") + } + + // check file with normal name which does exist. + _, err := os.Create(normalFileName) + if err != nil { + t.Error("failed to create test file") + } + defer os.Remove(normalFileName) + if logFileNameIsTooLong(normalFileName) { + t.Error("failed to check normal filename") + } +}