diff --git a/cmd/kubeadm/app/cmd/util/join.go b/cmd/kubeadm/app/cmd/util/join.go index cbf58238ab0..feded1d06d7 100644 --- a/cmd/kubeadm/app/cmd/util/join.go +++ b/cmd/kubeadm/app/cmd/util/join.go @@ -19,7 +19,7 @@ package util import ( "bytes" "crypto/x509" - "html/template" + "html/template" //nolint:depguard "strings" "k8s.io/client-go/tools/clientcmd" diff --git a/hack/golangci-hints.yaml b/hack/golangci-hints.yaml index 81e5e95e753..66e21cca6e3 100644 --- a/hack/golangci-hints.yaml +++ b/hack/golangci-hints.yaml @@ -254,6 +254,8 @@ linters: deny: - pkg: "github.com/google/go-cmp/cmp" desc: "cmp is allowed only in test files" + - pkg: "html/template" + desc: "template is allowed only in test files as it disables dead code elimination" forbidigo: analyze-types: true forbid: diff --git a/hack/golangci.yaml b/hack/golangci.yaml index 2306878a6bf..94dcd95e711 100644 --- a/hack/golangci.yaml +++ b/hack/golangci.yaml @@ -268,6 +268,8 @@ linters: deny: - pkg: "github.com/google/go-cmp/cmp" desc: "cmp is allowed only in test files" + - pkg: "html/template" + desc: "template is allowed only in test files as it disables dead code elimination" forbidigo: analyze-types: true forbid: diff --git a/hack/golangci.yaml.in b/hack/golangci.yaml.in index cebfd06fd5e..d6c7373af03 100644 --- a/hack/golangci.yaml.in +++ b/hack/golangci.yaml.in @@ -198,6 +198,8 @@ linters: deny: - pkg: "github.com/google/go-cmp/cmp" desc: "cmp is allowed only in test files" + - pkg: "html/template" + desc: "template is allowed only in test files as it disables dead code elimination" forbidigo: analyze-types: true forbid: diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/flags.go b/staging/src/k8s.io/apiserver/pkg/server/routes/flags.go index e7b4a7c6025..2b18af30a10 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/flags.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/flags.go @@ -18,7 +18,7 @@ package routes import ( "fmt" - "html/template" + "html/template" //nolint:depguard "io" "net/http" "path" @@ -56,12 +56,15 @@ func (f DebugFlags) Install(c *mux.PathRecorderMux, flag string, handler func(ht func (f DebugFlags) Index(w http.ResponseWriter, r *http.Request) { lock.RLock() defer lock.RUnlock() - if err := indexTmpl.Execute(w, registeredFlags); err != nil { + if err := indexTmpl(w, registeredFlags); err != nil { klog.Error(err) } } -var indexTmpl = template.Must(template.New("index").Parse(` +func indexTmpl(w io.Writer, flags map[string]debugFlag) error { + // avoid using a template to avoid disabling dead code elimination + // https://github.com/golang/go/issues/72895 + _, err := w.Write([]byte(` /debug/flags/ @@ -70,15 +73,27 @@ var indexTmpl = template.Must(template.New("index").Parse(`
flags:
-{{range .}} -{{.Flag}}
-{{end}} -
+`)) + if err != nil { + return err + } + + for _, flag := range flags { + _, err := fmt.Fprintf(w, `%s
+`, template.HTMLEscapeString(flag.Flag)) + if err != nil { + return err + } + } + + _, err = w.Write([]byte(`
full flags configurable
`)) + return err +} type debugFlag struct { Flag string diff --git a/staging/src/k8s.io/component-base/zpages/statusz/statusz.go b/staging/src/k8s.io/component-base/zpages/statusz/statusz.go index ef0814e3600..a60f6a0f894 100644 --- a/staging/src/k8s.io/component-base/zpages/statusz/statusz.go +++ b/staging/src/k8s.io/component-base/zpages/statusz/statusz.go @@ -17,9 +17,8 @@ limitations under the License. package statusz import ( - "bytes" "fmt" - "html/template" + "html" "math/rand" "net/http" "time" @@ -35,30 +34,11 @@ var ( const DefaultStatuszPath = "/statusz" -const ( - headerFmt = ` +const headerFmt = ` %s statusz Warning: This endpoint is not meant to be machine parseable, has no formatting compatibility guarantees and is for debugging purposes only. ` - dataTemplate = ` -Started{{.Delim}} {{.StartTime}} -Up{{.Delim}} {{.Uptime}} -Go version{{.Delim}} {{.GoVersion}} -Binary version{{.Delim}} {{.BinaryVersion}} -{{if .EmulationVersion}}Emulation version{{.Delim}} {{.EmulationVersion}}{{end}} -` -) - -type contentFields struct { - Delim string - StartTime string - Uptime string - GoVersion string - BinaryVersion string - EmulationVersion string -} - type mux interface { Handle(path string, handler http.Handler) } @@ -68,25 +48,10 @@ func NewRegistry(effectiveVersion compatibility.EffectiveVersion) statuszRegistr } func Install(m mux, componentName string, reg statuszRegistry) { - dataTmpl, err := initializeTemplates() - if err != nil { - klog.Errorf("error while parsing gotemplates: %v", err) - return - } - m.Handle(DefaultStatuszPath, handleStatusz(componentName, dataTmpl, reg)) + m.Handle(DefaultStatuszPath, handleStatusz(componentName, reg)) } -func initializeTemplates() (*template.Template, error) { - d := template.New("data") - dataTmpl, err := d.Parse(dataTemplate) - if err != nil { - return nil, err - } - - return dataTmpl, nil -} - -func handleStatusz(componentName string, dataTmpl *template.Template, reg statuszRegistry) http.HandlerFunc { +func handleStatusz(componentName string, reg statuszRegistry) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !httputil.AcceptableMediaType(r) { http.Error(w, httputil.ErrUnsupportedMediaType.Error(), http.StatusNotAcceptable) @@ -94,7 +59,7 @@ func handleStatusz(componentName string, dataTmpl *template.Template, reg status } fmt.Fprintf(w, headerFmt, componentName) - data, err := populateStatuszData(dataTmpl, reg) + data, err := populateStatuszData(reg) if err != nil { klog.Errorf("error while populating statusz data: %v", err) http.Error(w, "error while populating statusz data", http.StatusInternalServerError) @@ -106,31 +71,28 @@ func handleStatusz(componentName string, dataTmpl *template.Template, reg status } } -func populateStatuszData(tmpl *template.Template, reg statuszRegistry) (string, error) { - if tmpl == nil { - return "", fmt.Errorf("received nil template") - } - +func populateStatuszData(reg statuszRegistry) (string, error) { randomIndex := rand.Intn(len(delimiters)) - data := contentFields{ - Delim: delimiters[randomIndex], - StartTime: reg.processStartTime().Format(time.UnixDate), - Uptime: uptime(reg.processStartTime()), - GoVersion: reg.goVersion(), - BinaryVersion: reg.binaryVersion().String(), - } + delim := html.EscapeString(delimiters[randomIndex]) + startTime := html.EscapeString(reg.processStartTime().Format(time.UnixDate)) + uptime := html.EscapeString(uptime(reg.processStartTime())) + goVersion := html.EscapeString(reg.goVersion()) + binaryVersion := html.EscapeString(reg.binaryVersion().String()) + var emulationVersion string if reg.emulationVersion() != nil { - data.EmulationVersion = reg.emulationVersion().String() + emulationVersion = fmt.Sprintf(`Emulation version%s %s`, delim, html.EscapeString(reg.emulationVersion().String())) } - var tpl bytes.Buffer - err := tmpl.Execute(&tpl, data) - if err != nil { - return "", fmt.Errorf("error executing statusz template: %w", err) - } + status := fmt.Sprintf(` +Started%[1]s %[2]s +Up%[1]s %[3]s +Go version%[1]s %[4]s +Binary version%[1]s %[5]s +%[6]s +`, delim, startTime, uptime, goVersion, binaryVersion, emulationVersion) - return tpl.String(), nil + return status, nil } func uptime(t time.Time) string {