Change:
Hello and I were fuzzing the k8s (via ) and found out following bug. Getting logs from unicode logpath via API causes internal server error. The API endpoint is . Response with non-500 HTTP status code We were fuzzing k8s locally via minikube. minukube ca certificates k8s IP address the IP to as access token and export it as request Kubernetes version (use ):Cloud provider or hardware configuration: minikube with virtual-box driver OS (e.g: ): Ubuntu 18.04.5 LTS (bionic) Kernel (e.g. ): Linux pine 4.15.0-140-generic -Ubuntu SMP Fri Mar 19 14:12:35 UTC 2021 x8664 x8664 x86_64 GNU/Linux Install tools: downloaded precompiled binary minikube version: v1.19.0 (commit: )
/sig api-machinery
/assign I will look into it.
thank you , please keep us posted! /triage accepted
For clarity are you saying that the fuzzed URL is valid or invalid UTF-8 (URL-encoded)?
It's valid UTF-8
Actually, according to my test,this bug comes from http.ServeFile which replies to the request with the contents of the named file or directory. When giving too long(On Linux: The maximum length for a file name is 255 bytes. The maximum combined length of both the file name and path name is 4096 bytes.) filename or pathname to http.ServeFile,it will return code 500(file name too long) rather than 404(no such file or directory). And when filename is not that long, unicode path work correctly too. Here is my simple test below: And since /logs is the only place use http.ServeFile, there is no other api has the same problem. ! So I will add a length check before calling http.ServeFile to solve this. Does that sound good to you?
Maybe 400 - bad request would be more suitable response code. But I'm not a maintainer so it's not up to me to decide.
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-contributor-experience at . /lifecycle stale
The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules: After 90d of inactivity, is applied After 30d of inactivity since was applied, is applied After 30d of inactivity since was applied, the issue is closed You can: Mark this issue or PR as fresh with Close this issue or PR with Offer to help out with [Issue Triage][1] Please send feedback to sig-contributor-experience at . /lifecycle rotten [1]:
The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules: After 90d of inactivity, is applied After 30d of inactivity since was applied, is applied After 30d of inactivity since was applied, the issue is closed You can: Reopen this issue or PR with Mark this issue or PR as fresh with Offer to help out with [Issue Triage][1] Please send feedback to sig-contributor-experience at . /close [1]:
Closing this issue. <detailsIn response to : The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs. After 90d of inactivity, is applied After 30d of inactivity since was applied, is applied After 30d of inactivity since was applied, the issue is closedReopen this issue or PR with Mark this issue or PR as fresh with Offer to help out with [Issue Triage][1] Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details

Discussion:
import ( "net/http" <ins> "os" </ins> "path" <ins> "syscall" </ins> "github.com/emicklei/go-restful" )

func logFileHandler(req *restful.Request, resp *restful.Response) { logdir := "/var/log" actual := path.Join(logdir, req.PathParameter("logpath")) <ins> // check filename length first, return 404 if it's oversize. if logFileNameIsTooLong(actual) { http.Error(resp, "file not found", http.StatusNotFound) return } </ins> http.ServeFile(resp.ResponseWriter, req.Request, actual) }

logdir := "/var/log" http.ServeFile(resp.ResponseWriter, req.Request, logdir) } <ins> // 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 } </ins>

<ins> /* 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") } } </ins>