mirror of
https://github.com/coredns/coredns.git
synced 2026-04-04 19:25:40 -04:00
fix(kubernetes): sanitize non-UTF-8 host in metrics (#7998)
This commit is contained in:
@@ -3,7 +3,9 @@ package kubernetes
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/coredns/coredns/plugin"
|
"github.com/coredns/coredns/plugin"
|
||||||
|
|
||||||
@@ -64,7 +66,7 @@ type latencyAdapter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *latencyAdapter) Observe(_ context.Context, verb string, u url.URL, latency time.Duration) {
|
func (l *latencyAdapter) Observe(_ context.Context, verb string, u url.URL, latency time.Duration) {
|
||||||
l.m.WithLabelValues(verb, u.Host).Observe(latency.Seconds())
|
l.m.WithLabelValues(verb, sanitizeLabelValue(u.Host)).Observe(latency.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
type resultAdapter struct {
|
type resultAdapter struct {
|
||||||
@@ -72,5 +74,14 @@ type resultAdapter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *resultAdapter) Increment(_ context.Context, code, method, host string) {
|
func (r *resultAdapter) Increment(_ context.Context, code, method, host string) {
|
||||||
r.m.WithLabelValues(code, method, host).Inc()
|
r.m.WithLabelValues(code, method, sanitizeLabelValue(host)).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanitizeLabelValue ensures the string is valid UTF-8, which is required by
|
||||||
|
// Prometheus for label values. Invalid bytes are replaced with U+FFFD.
|
||||||
|
func sanitizeLabelValue(s string) string {
|
||||||
|
if utf8.ValidString(s) {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return strings.ToValidUTF8(s, "\uFFFD")
|
||||||
}
|
}
|
||||||
|
|||||||
27
plugin/kubernetes/metrics_test.go
Normal file
27
plugin/kubernetes/metrics_test.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package kubernetes
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSanitizeLabelValue(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"valid ASCII", "example.com", "example.com"},
|
||||||
|
{"valid UTF-8", "例え.jp", "例え.jp"},
|
||||||
|
{"empty string", "", ""},
|
||||||
|
{"invalid single byte", "host\xff:443", "host\uFFFD:443"},
|
||||||
|
{"consecutive invalid bytes", "\xff\xfe\xfd", "\uFFFD"},
|
||||||
|
{"mixed valid and invalid", "ok\xffok\xfeok", "ok\uFFFDok\uFFFDok"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got := sanitizeLabelValue(tc.input)
|
||||||
|
if got != tc.expected {
|
||||||
|
t.Errorf("sanitizeLabelValue(%q) = %q, want %q", tc.input, got, tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,22 @@ acl
|
|||||||
"hosts#\x90\xD0{lc\x0C{\n" +
|
"hosts#\x90\xD0{lc\x0C{\n" +
|
||||||
"'{mport\xEF1\x0C}\x0B''",
|
"'{mport\xEF1\x0C}\x0B''",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// A kubernetes endpoint URL with invalid UTF-8 caused a
|
||||||
|
// panic in Prometheus WithLabelValues.
|
||||||
|
// See OSS-Fuzz issue: https://issues.oss-fuzz.com/issues/498472468
|
||||||
|
name: "FuzzCore_InvalidUTF8InKubernetesEndpoint",
|
||||||
|
corefile: "\xf6\xe6*S65558::65535\n" +
|
||||||
|
"kubernetes idd\x0cd\xc8:0\x00,\x13" +
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd" +
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00-\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
|
||||||
|
"\t{\tendpoint m\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||||
|
"\xff\xff\xff\xffFFFFFF%FFFFFFFF\xff\xff\xff\xff\xff" +
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||||
|
"\xff\xff\tuil{ticll{ticl\x00,1:*\x0cd}\x0c}",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
|||||||
Reference in New Issue
Block a user