Skip to content

Commit e9fea0b

Browse files
[AUTO-CHERRYPICK] fix cve-2022-21698 in local-path-provisioner - branch main (#7626)
Fixes CVE-2022-21698 for local-path-provisioner. The vulnerability is in the client_golang go module, which is vendored in this package. Fix is to apply a (modified) patch to the vendored code. Co-authored-by: Tobias Brick <39196763+tobiasb-ms@users.noreply.github.com>
1 parent f5bae07 commit e9fea0b

2 files changed

Lines changed: 371 additions & 1 deletion

File tree

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
From 253029f7ffbade99588df59a8b89a35d99197fe0 Mon Sep 17 00:00:00 2001
2+
From: Tobias Brick <tobiasb@microsoft.com>
3+
Date: Tue, 18 Jan 2022 10:19:28 +0100
4+
Subject: [PATCH] Port upstream patch
5+
https://github.com/prometheus/client_golang/commit/9075cdf61646b5adf54d3ba77a0e4f6c65cb4fd7
6+
7+
Differences:
8+
- Removed tests
9+
- Removed some comments that don't merge
10+
- Line numbers and such
11+
12+
Based on:
13+
14+
From 9075cdf61646b5adf54d3ba77a0e4f6c65cb4fd7 Mon Sep 17 00:00:00 2001
15+
From: Kemal Akkoyun <kakkoyun@users.noreply.github.com>
16+
Date: Tue, 18 Jan 2022 10:19:28 +0100
17+
Subject: [PATCH] promhttp: Check validity of method and code label values
18+
(#962)
19+
20+
* Check validity of method and code label values
21+
22+
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
23+
24+
* Use more flexibly functional option pattern for configuration
25+
26+
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
27+
28+
* Update documentation
29+
30+
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
31+
32+
* Simplify
33+
34+
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
35+
36+
* Fix inconsistent method naming
37+
38+
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
39+
---
40+
prometheus/promhttp/instrument_client.go | 28 ++++++--
41+
prometheus/promhttp/instrument_server.go | 82 ++++++++++++++++++------
42+
prometheus/promhttp/option.go | 31 +++++++++
43+
3 files changed, 116 insertions(+), 25 deletions(-)
44+
create mode 100644 prometheus/promhttp/option.go
45+
46+
diff --git a/prometheus/promhttp/instrument_client.go b/prometheus/promhttp/instrument_client.go
47+
index 83c49b6..861b4d2 100644
48+
--- a/prometheus/promhttp/instrument_client.go
49+
+++ b/prometheus/promhttp/instrument_client.go
50+
@@ -49,7 +49,10 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
51+
// http.RoundTripper to observe the request result with the provided CounterVec.
52+
// The CounterVec must have zero, one, or two non-const non-curried labels. For
53+
// those, the only allowed label names are "code" and "method". The function
54+
-// panics otherwise. Partitioning of the CounterVec happens by HTTP status code
55+
+// panics otherwise. For the "method" label a predefined default label value set
56+
+// is used to filter given values. Values besides predefined values will count
57+
+// as `unknown` method.`WithExtraMethods` can be used to add more
58+
+// methods to the set. Partitioning of the CounterVec happens by HTTP status code
59+
// and/or HTTP method if the respective instance label names are present in the
60+
// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
61+
//
62+
@@ -57,13 +60,18 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
63+
// is not incremented.
64+
//
65+
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
66+
-func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc {
67+
+func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
68+
+ rtOpts := &option{}
69+
+ for _, o := range opts {
70+
+ o(rtOpts)
71+
+ }
72+
+
73+
code, method := checkLabels(counter)
74+
75+
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
76+
resp, err := next.RoundTrip(r)
77+
if err == nil {
78+
- counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc()
79+
+ counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Inc()
80+
}
81+
return resp, err
82+
})
83+
@@ -73,7 +81,10 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
84+
// http.RoundTripper to observe the request duration with the provided
85+
// ObserverVec. The ObserverVec must have zero, one, or two non-const
86+
// non-curried labels. For those, the only allowed label names are "code" and
87+
-// "method". The function panics otherwise. The Observe method of the Observer
88+
+// "method". The function panics otherwise. For the "method" label a predefined
89+
+// default label value set is used to filter given values. Values besides
90+
+// predefined values will count as `unknown` method. `WithExtraMethods`
91+
+// can be used to add more methods to the set. The Observe method of the Observer
92+
// in the ObserverVec is called with the request duration in
93+
// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
94+
// respective instance label names are present in the ObserverVec. For
95+
@@ -85,14 +96,19 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
96+
//
97+
// Note that this method is only guaranteed to never observe negative durations
98+
// if used with Go1.9+.
99+
-func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc {
100+
+func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
101+
+ rtOpts := &option{}
102+
+ for _, o := range opts {
103+
+ o(rtOpts)
104+
+ }
105+
+
106+
code, method := checkLabels(obs)
107+
108+
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
109+
start := time.Now()
110+
resp, err := next.RoundTrip(r)
111+
if err == nil {
112+
- obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds())
113+
+ obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Observe(time.Since(start).Seconds())
114+
}
115+
return resp, err
116+
})
117+
diff --git a/prometheus/promhttp/instrument_server.go b/prometheus/promhttp/instrument_server.go
118+
index 9db2438..91802f8 100644
119+
--- a/prometheus/promhttp/instrument_server.go
120+
+++ b/prometheus/promhttp/instrument_server.go
121+
@@ -58,7 +58,12 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
122+
//
123+
// Note that this method is only guaranteed to never observe negative durations
124+
// if used with Go1.9+.
125+
-func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
126+
+func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
127+
+ mwOpts := &option{}
128+
+ for _, o := range opts {
129+
+ o(mwOpts)
130+
+ }
131+
+
132+
code, method := checkLabels(obs)
133+
134+
if code {
135+
@@ -67,14 +72,14 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
136+
d := newDelegator(w, nil)
137+
next.ServeHTTP(d, r)
138+
139+
- obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds())
140+
+ obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
141+
})
142+
}
143+
144+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
145+
now := time.Now()
146+
next.ServeHTTP(w, r)
147+
- obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds())
148+
+ obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
149+
})
150+
}
151+
152+
@@ -91,20 +96,25 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
153+
// If the wrapped Handler panics, the Counter is not incremented.
154+
//
155+
// See the example for InstrumentHandlerDuration for example usage.
156+
-func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc {
157+
+func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, opts ...Option) http.HandlerFunc {
158+
+ mwOpts := &option{}
159+
+ for _, o := range opts {
160+
+ o(mwOpts)
161+
+ }
162+
+
163+
code, method := checkLabels(counter)
164+
165+
if code {
166+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
167+
d := newDelegator(w, nil)
168+
next.ServeHTTP(d, r)
169+
- counter.With(labels(code, method, r.Method, d.Status())).Inc()
170+
+ counter.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Inc()
171+
})
172+
}
173+
174+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
175+
next.ServeHTTP(w, r)
176+
- counter.With(labels(code, method, r.Method, 0)).Inc()
177+
+ counter.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Inc()
178+
})
179+
}
180+
181+
@@ -126,13 +136,18 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
182+
// if used with Go1.9+.
183+
//
184+
// See the example for InstrumentHandlerDuration for example usage.
185+
-func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
186+
+func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
187+
+ mwOpts := &option{}
188+
+ for _, o := range opts {
189+
+ o(mwOpts)
190+
+ }
191+
+
192+
code, method := checkLabels(obs)
193+
194+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
195+
now := time.Now()
196+
d := newDelegator(w, func(status int) {
197+
- obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds())
198+
+ obs.With(labels(code, method, r.Method, status, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
199+
})
200+
next.ServeHTTP(d, r)
201+
})
202+
@@ -154,7 +169,12 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
203+
// If the wrapped Handler panics, no values are reported.
204+
//
205+
// See the example for InstrumentHandlerDuration for example usage.
206+
-func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
207+
+func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
208+
+ mwOpts := &option{}
209+
+ for _, o := range opts {
210+
+ o(mwOpts)
211+
+ }
212+
+
213+
code, method := checkLabels(obs)
214+
215+
if code {
216+
@@ -162,14 +182,14 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
217+
d := newDelegator(w, nil)
218+
next.ServeHTTP(d, r)
219+
size := computeApproximateRequestSize(r)
220+
- obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size))
221+
+ obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(size))
222+
})
223+
}
224+
225+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
226+
next.ServeHTTP(w, r)
227+
size := computeApproximateRequestSize(r)
228+
- obs.With(labels(code, method, r.Method, 0)).Observe(float64(size))
229+
+ obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(float64(size))
230+
})
231+
}
232+
233+
@@ -189,12 +209,18 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
234+
// If the wrapped Handler panics, no values are reported.
235+
//
236+
// See the example for InstrumentHandlerDuration for example usage.
237+
-func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler {
238+
+func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.Handler {
239+
+ mwOpts := &option{}
240+
+ for _, o := range opts {
241+
+ o(mwOpts)
242+
+ }
243+
+
244+
code, method := checkLabels(obs)
245+
+
246+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
247+
d := newDelegator(w, nil)
248+
next.ServeHTTP(d, r)
249+
- obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written()))
250+
+ obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(d.Written()))
251+
})
252+
}
253+
254+
@@ -279,7 +305,7 @@ func isLabelCurried(c prometheus.Collector, label string) bool {
255+
// unnecessary allocations on each request.
256+
var emptyLabels = prometheus.Labels{}
257+
258+
-func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
259+
+func labels(code, method bool, reqMethod string, status int, extraMethods ...string) prometheus.Labels {
260+
if !(code || method) {
261+
return emptyLabels
262+
}
263+
@@ -289,7 +315,7 @@ func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
264+
labels["code"] = sanitizeCode(status)
265+
}
266+
if method {
267+
- labels["method"] = sanitizeMethod(reqMethod)
268+
+ labels["method"] = sanitizeMethod(reqMethod, extraMethods...)
269+
}
270+
271+
return labels
272+
@@ -319,7 +345,12 @@ func computeApproximateRequestSize(r *http.Request) int {
273+
return s
274+
}
275+
276+
-func sanitizeMethod(m string) string {
277+
+// If the wrapped http.Handler has a known method, it will be sanitized and returned.
278+
+// Otherwise, "unknown" will be returned. The known method list can be extended
279+
+// as needed by using extraMethods parameter.
280+
+func sanitizeMethod(m string, extraMethods ...string) string {
281+
+ // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for
282+
+ // the methods chosen as default.
283+
switch m {
284+
case "GET", "get":
285+
return "get"
286+
@@ -337,15 +368,25 @@ func sanitizeMethod(m string) string {
287+
return "options"
288+
case "NOTIFY", "notify":
289+
return "notify"
290+
+ case "TRACE", "trace":
291+
+ return "trace"
292+
+ case "PATCH", "patch":
293+
+ return "patch"
294+
default:
295+
- return strings.ToLower(m)
296+
+ for _, method := range extraMethods {
297+
+ if strings.EqualFold(m, method) {
298+
+ return strings.ToLower(m)
299+
+ }
300+
+ }
301+
+ return "unknown"
302+
}
303+
}
304+
305+
// If the wrapped http.Handler has not set a status code, i.e. the value is
306+
-// currently 0, santizeCode will return 200, for consistency with behavior in
307+
+// currently 0, sanitizeCode will return 200, for consistency with behavior in
308+
// the stdlib.
309+
func sanitizeCode(s int) string {
310+
+ // See for accepted codes https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
311+
switch s {
312+
case 100:
313+
return "100"
314+
@@ -442,6 +483,9 @@ func sanitizeCode(s int) string {
315+
return "511"
316+
317+
default:
318+
- return strconv.Itoa(s)
319+
+ if s >= 100 && s <= 599 {
320+
+ return strconv.Itoa(s)
321+
+ }
322+
+ return "unknown"
323+
}
324+
}
325+
diff --git a/prometheus/promhttp/option.go b/prometheus/promhttp/option.go
326+
new file mode 100644
327+
index 0000000..35e41bd
328+
--- /dev/null
329+
+++ b/prometheus/promhttp/option.go
330+
@@ -0,0 +1,31 @@
331+
+// Copyright 2022 The Prometheus Authors
332+
+// Licensed under the Apache License, Version 2.0 (the "License");
333+
+// you may not use this file except in compliance with the License.
334+
+// You may obtain a copy of the License at
335+
+//
336+
+// http://www.apache.org/licenses/LICENSE-2.0
337+
+//
338+
+// Unless required by applicable law or agreed to in writing, software
339+
+// distributed under the License is distributed on an "AS IS" BASIS,
340+
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
341+
+// See the License for the specific language governing permissions and
342+
+// limitations under the License.
343+
+
344+
+package promhttp
345+
+
346+
+// Option are used to configure a middleware or round tripper..
347+
+type Option func(*option)
348+
+
349+
+type option struct {
350+
+ extraMethods []string
351+
+}
352+
+
353+
+// WithExtraMethods adds additional HTTP methods to the list of allowed methods.
354+
+// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for the default list.
355+
+//
356+
+// See the example for ExampleInstrumentHandlerWithExtraMethods for example usage.
357+
+func WithExtraMethods(methods ...string) Option {
358+
+ return func(o *option) {
359+
+ o.extraMethods = methods
360+
+ }
361+
+}
362+
--
363+
2.33.8
364+

0 commit comments

Comments
 (0)