[AUTO-CHERRYPICK] patch CVE-2022-21698 in application-gateway-kubernetes-ingress - branch main (#7548)

This is an auto-generated pull request to cherry-pick commit f0d5827 to main. Original PR: #7542
Co-authored-by: Tobias Brick <39196763+tobiasb-ms@users.noreply.github.com>
This commit is contained in:
CBL-Mariner-Bot 2024-01-30 16:05:56 -08:00 committed by GitHub
parent 46a4d292cd
commit 790ebdc946
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 374 additions and 5 deletions

View File

@ -0,0 +1,364 @@
From 253029f7ffbade99588df59a8b89a35d99197fe0 Mon Sep 17 00:00:00 2001
From: Tobias Brick <tobiasb@microsoft.com>
Date: Tue, 18 Jan 2022 10:19:28 +0100
Subject: [PATCH] Port upstream patch
https://github.com/prometheus/client_golang/commit/9075cdf61646b5adf54d3ba77a0e4f6c65cb4fd7
Differences:
- Removed tests
- Removed some comments that don't merge
- Line numbers and such
Based on:
From 9075cdf61646b5adf54d3ba77a0e4f6c65cb4fd7 Mon Sep 17 00:00:00 2001
From: Kemal Akkoyun <kakkoyun@users.noreply.github.com>
Date: Tue, 18 Jan 2022 10:19:28 +0100
Subject: [PATCH] promhttp: Check validity of method and code label values
(#962)
* Check validity of method and code label values
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
* Use more flexibly functional option pattern for configuration
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
* Update documentation
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
* Simplify
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
* Fix inconsistent method naming
Signed-off-by: Kemal Akkoyun <kakkoyun@gmail.com>
---
prometheus/promhttp/instrument_client.go | 28 ++++++--
prometheus/promhttp/instrument_server.go | 82 ++++++++++++++++++------
prometheus/promhttp/option.go | 31 +++++++++
3 files changed, 116 insertions(+), 25 deletions(-)
create mode 100644 prometheus/promhttp/option.go
diff --git a/prometheus/promhttp/instrument_client.go b/prometheus/promhttp/instrument_client.go
index 83c49b6..861b4d2 100644
--- a/prometheus/promhttp/instrument_client.go
+++ b/prometheus/promhttp/instrument_client.go
@@ -49,7 +49,10 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
// http.RoundTripper to observe the request result with the provided CounterVec.
// The CounterVec must have zero, one, or two non-const non-curried labels. For
// those, the only allowed label names are "code" and "method". The function
-// panics otherwise. Partitioning of the CounterVec happens by HTTP status code
+// panics otherwise. For the "method" label a predefined default label value set
+// is used to filter given values. Values besides predefined values will count
+// as `unknown` method.`WithExtraMethods` can be used to add more
+// methods to the set. Partitioning of the CounterVec happens by HTTP status code
// and/or HTTP method if the respective instance label names are present in the
// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
//
@@ -57,13 +60,18 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
// is not incremented.
//
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
-func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc {
+func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
+ rtOpts := &option{}
+ for _, o := range opts {
+ o(rtOpts)
+ }
+
code, method := checkLabels(counter)
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
resp, err := next.RoundTrip(r)
if err == nil {
- counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc()
+ counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Inc()
}
return resp, err
})
@@ -73,7 +81,10 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
// http.RoundTripper to observe the request duration with the provided
// ObserverVec. The ObserverVec must have zero, one, or two non-const
// non-curried labels. For those, the only allowed label names are "code" and
-// "method". The function panics otherwise. The Observe method of the Observer
+// "method". The function panics otherwise. For the "method" label a predefined
+// default label value set is used to filter given values. Values besides
+// predefined values will count as `unknown` method. `WithExtraMethods`
+// can be used to add more methods to the set. The Observe method of the Observer
// in the ObserverVec is called with the request duration in
// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
// respective instance label names are present in the ObserverVec. For
@@ -85,14 +96,19 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
//
// Note that this method is only guaranteed to never observe negative durations
// if used with Go1.9+.
-func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc {
+func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
+ rtOpts := &option{}
+ for _, o := range opts {
+ o(rtOpts)
+ }
+
code, method := checkLabels(obs)
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
start := time.Now()
resp, err := next.RoundTrip(r)
if err == nil {
- obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds())
+ obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Observe(time.Since(start).Seconds())
}
return resp, err
})
diff --git a/prometheus/promhttp/instrument_server.go b/prometheus/promhttp/instrument_server.go
index 9db2438..91802f8 100644
--- a/prometheus/promhttp/instrument_server.go
+++ b/prometheus/promhttp/instrument_server.go
@@ -58,7 +58,12 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
//
// Note that this method is only guaranteed to never observe negative durations
// if used with Go1.9+.
-func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
+ mwOpts := &option{}
+ for _, o := range opts {
+ o(mwOpts)
+ }
+
code, method := checkLabels(obs)
if code {
@@ -67,14 +72,14 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
d := newDelegator(w, nil)
next.ServeHTTP(d, r)
- obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds())
+ obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
})
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
now := time.Now()
next.ServeHTTP(w, r)
- obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds())
+ obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
})
}
@@ -91,20 +96,25 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
// If the wrapped Handler panics, the Counter is not incremented.
//
// See the example for InstrumentHandlerDuration for example usage.
-func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc {
+func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, opts ...Option) http.HandlerFunc {
+ mwOpts := &option{}
+ for _, o := range opts {
+ o(mwOpts)
+ }
+
code, method := checkLabels(counter)
if code {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
d := newDelegator(w, nil)
next.ServeHTTP(d, r)
- counter.With(labels(code, method, r.Method, d.Status())).Inc()
+ counter.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Inc()
})
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r)
- counter.With(labels(code, method, r.Method, 0)).Inc()
+ counter.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Inc()
})
}
@@ -126,13 +136,18 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
// if used with Go1.9+.
//
// See the example for InstrumentHandlerDuration for example usage.
-func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
+ mwOpts := &option{}
+ for _, o := range opts {
+ o(mwOpts)
+ }
+
code, method := checkLabels(obs)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
now := time.Now()
d := newDelegator(w, func(status int) {
- obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds())
+ obs.With(labels(code, method, r.Method, status, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
})
next.ServeHTTP(d, r)
})
@@ -154,7 +169,12 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
// If the wrapped Handler panics, no values are reported.
//
// See the example for InstrumentHandlerDuration for example usage.
-func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
+ mwOpts := &option{}
+ for _, o := range opts {
+ o(mwOpts)
+ }
+
code, method := checkLabels(obs)
if code {
@@ -162,14 +182,14 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
d := newDelegator(w, nil)
next.ServeHTTP(d, r)
size := computeApproximateRequestSize(r)
- obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size))
+ obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(size))
})
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r)
size := computeApproximateRequestSize(r)
- obs.With(labels(code, method, r.Method, 0)).Observe(float64(size))
+ obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(float64(size))
})
}
@@ -189,12 +209,18 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
// If the wrapped Handler panics, no values are reported.
//
// See the example for InstrumentHandlerDuration for example usage.
-func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler {
+func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.Handler {
+ mwOpts := &option{}
+ for _, o := range opts {
+ o(mwOpts)
+ }
+
code, method := checkLabels(obs)
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
d := newDelegator(w, nil)
next.ServeHTTP(d, r)
- obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written()))
+ obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(d.Written()))
})
}
@@ -279,7 +305,7 @@ func isLabelCurried(c prometheus.Collector, label string) bool {
// unnecessary allocations on each request.
var emptyLabels = prometheus.Labels{}
-func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
+func labels(code, method bool, reqMethod string, status int, extraMethods ...string) prometheus.Labels {
if !(code || method) {
return emptyLabels
}
@@ -289,7 +315,7 @@ func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
labels["code"] = sanitizeCode(status)
}
if method {
- labels["method"] = sanitizeMethod(reqMethod)
+ labels["method"] = sanitizeMethod(reqMethod, extraMethods...)
}
return labels
@@ -319,7 +345,12 @@ func computeApproximateRequestSize(r *http.Request) int {
return s
}
-func sanitizeMethod(m string) string {
+// If the wrapped http.Handler has a known method, it will be sanitized and returned.
+// Otherwise, "unknown" will be returned. The known method list can be extended
+// as needed by using extraMethods parameter.
+func sanitizeMethod(m string, extraMethods ...string) string {
+ // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for
+ // the methods chosen as default.
switch m {
case "GET", "get":
return "get"
@@ -337,15 +368,25 @@ func sanitizeMethod(m string) string {
return "options"
case "NOTIFY", "notify":
return "notify"
+ case "TRACE", "trace":
+ return "trace"
+ case "PATCH", "patch":
+ return "patch"
default:
- return strings.ToLower(m)
+ for _, method := range extraMethods {
+ if strings.EqualFold(m, method) {
+ return strings.ToLower(m)
+ }
+ }
+ return "unknown"
}
}
// If the wrapped http.Handler has not set a status code, i.e. the value is
-// currently 0, santizeCode will return 200, for consistency with behavior in
+// currently 0, sanitizeCode will return 200, for consistency with behavior in
// the stdlib.
func sanitizeCode(s int) string {
+ // See for accepted codes https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
switch s {
case 100:
return "100"
@@ -442,6 +483,9 @@ func sanitizeCode(s int) string {
return "511"
default:
- return strconv.Itoa(s)
+ if s >= 100 && s <= 599 {
+ return strconv.Itoa(s)
+ }
+ return "unknown"
}
}
diff --git a/prometheus/promhttp/option.go b/prometheus/promhttp/option.go
new file mode 100644
index 0000000..35e41bd
--- /dev/null
+++ b/prometheus/promhttp/option.go
@@ -0,0 +1,31 @@
+// Copyright 2022 The Prometheus 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 promhttp
+
+// Option are used to configure a middleware or round tripper..
+type Option func(*option)
+
+type option struct {
+ extraMethods []string
+}
+
+// WithExtraMethods adds additional HTTP methods to the list of allowed methods.
+// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for the default list.
+//
+// See the example for ExampleInstrumentHandlerWithExtraMethods for example usage.
+func WithExtraMethods(methods ...string) Option {
+ return func(o *option) {
+ o.extraMethods = methods
+ }
+}
--
2.33.8

View File

@ -2,7 +2,7 @@
Summary: Application Gateway Ingress Controller
Name: application-gateway-kubernetes-ingress
Version: 1.4.0
Release: 16%{?dist}
Release: 17%{?dist}
License: MIT
Vendor: Microsoft Corporation
Distribution: Mariner
@ -24,7 +24,8 @@ Source0: %{name}-%{version}.tar.gz
# -cf %%{name}-%%{version}-vendor.tar.gz vendor
#
Source1: %{name}-%{version}-vendor.tar.gz
# If upstream ever upgrades client_goland to 1.11.1, we can get rid of this patch.
Patch0: CVE-2022-21698.patch
BuildRequires: golang >= 1.13
%description
@ -32,12 +33,12 @@ This is an ingress controller that can be run on Azure Kubernetes Service (AKS)
to act as the ingress for an AKS cluster.
%prep
%autosetup
%build
%autosetup -N
rm -rf vendor
tar -xf %{SOURCE1} --no-same-owner
%patch 0 -p1 -d vendor/github.com/prometheus/client_golang
%build
export VERSION=%{version}
export VERSION_PATH=github.com/Azure/application-gateway-kubernetes-ingress/pkg/version
@ -54,6 +55,10 @@ cp appgw-ingress %{buildroot}%{_bindir}/
%{_bindir}/appgw-ingress
%changelog
* Mon Jan 01 2024 Tobias Brick <tobiasb@microsoft.com> - 1.4.0-17
- Patch for CVE-2022-21698
- Moved vendored tarball extraction into %prep and changed from %autosetup to %setup
* Mon Oct 16 2023 CBL-Mariner Servicing Account <cblmargh@microsoft.com> - 1.4.0-16
- Bump release to rebuild with go 1.20.9