From 832259cb17a9f814e20ce813325c05c47cefa9b5 Mon Sep 17 00:00:00 2001 From: starlet-dx <15929766099@163.com> Date: Thu, 17 Mar 2022 10:14:38 +0800 Subject: [PATCH] Fix CVE-2022-21702 --- CVE-2022-21702.patch | 191 +++++++++++++++++++++++++++++++++++++++++++ grafana.spec | 8 +- 2 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 CVE-2022-21702.patch diff --git a/CVE-2022-21702.patch b/CVE-2022-21702.patch new file mode 100644 index 0000000..f60766d --- /dev/null +++ b/CVE-2022-21702.patch @@ -0,0 +1,191 @@ +From 27726868b3d7c613844b55cd209ca93645c99b85 Mon Sep 17 00:00:00 2001 +From: Marcus Efraimsson +Date: Fri, 21 Jan 2022 16:43:04 +0100 +Subject: [PATCH] [v7.5.x] Fix for CVE-2022-21702 (#226) + +Fix for CVE-2022-21702 +--- + pkg/api/pluginproxy/ds_proxy.go | 1 + + pkg/api/pluginproxy/ds_proxy_test.go | 12 +++++++ + pkg/api/pluginproxy/pluginproxy.go | 8 ++++- + pkg/api/pluginproxy/pluginproxy_test.go | 44 +++++++++++++++++++++++ + pkg/plugins/backendplugin/manager.go | 1 + + pkg/plugins/backendplugin/manager_test.go | 9 ++++- + pkg/util/proxyutil/proxyutil.go | 6 ++++ + 7 files changed, 79 insertions(+), 2 deletions(-) + +diff --git a/pkg/api/pluginproxy/ds_proxy.go b/pkg/api/pluginproxy/ds_proxy.go +index e5cf53dacc958..b5537ba6eb941 100644 +--- a/pkg/api/pluginproxy/ds_proxy.go ++++ b/pkg/api/pluginproxy/ds_proxy.go +@@ -49,6 +49,7 @@ func (t *handleResponseTransport) RoundTrip(req *http.Request) (*http.Response, + return nil, err + } + res.Header.Del("Set-Cookie") ++ proxyutil.SetProxyResponseHeaders(res.Header) + return res, nil + } + +diff --git a/pkg/api/pluginproxy/ds_proxy_test.go b/pkg/api/pluginproxy/ds_proxy_test.go +index 4f61e2055c471..be4bd8b38e7db 100644 +--- a/pkg/api/pluginproxy/ds_proxy_test.go ++++ b/pkg/api/pluginproxy/ds_proxy_test.go +@@ -605,6 +605,18 @@ func TestDataSourceProxy_requestHandling(t *testing.T) { + assert.Equal(t, "important_cookie=important_value", proxy.ctx.Resp.Header().Get("Set-Cookie")) + }) + ++ t.Run("When response should set Content-Security-Policy header", func(t *testing.T) { ++ ctx, ds := setUp(t) ++ dsPlugin := &plugins.DataSourcePlugin{} ++ proxy, err := NewDataSourceProxy(ds, dsPlugin, ctx, "/render", &setting.Cfg{}) ++ require.NoError(t, err) ++ ++ proxy.HandleRequest() ++ ++ require.NoError(t, writeErr) ++ assert.Equal(t, "sandbox", proxy.ctx.Resp.Header().Get("Content-Security-Policy")) ++ }) ++ + t.Run("Data source returns status code 401", func(t *testing.T) { + ctx, ds := setUp(t, setUpCfg{ + writeCb: func(w http.ResponseWriter, r *http.Request) { +diff --git a/pkg/api/pluginproxy/pluginproxy.go b/pkg/api/pluginproxy/pluginproxy.go +index 34e88459ef37b..5b0c3e436c25d 100644 +--- a/pkg/api/pluginproxy/pluginproxy.go ++++ b/pkg/api/pluginproxy/pluginproxy.go +@@ -71,5 +71,11 @@ func NewApiPluginProxy(ctx *models.ReqContext, proxyPath string, route *plugins. + } + } + +- return &httputil.ReverseProxy{Director: director} ++ return &httputil.ReverseProxy{Director: director, ModifyResponse: modifyResponse} ++} ++ ++func modifyResponse(resp *http.Response) error { ++ proxyutil.SetProxyResponseHeaders(resp.Header) ++ ++ return nil + } +diff --git a/pkg/api/pluginproxy/pluginproxy_test.go b/pkg/api/pluginproxy/pluginproxy_test.go +index 7b538139bbc14..b9873ef4f3973 100644 +--- a/pkg/api/pluginproxy/pluginproxy_test.go ++++ b/pkg/api/pluginproxy/pluginproxy_test.go +@@ -2,6 +2,7 @@ package pluginproxy + + import ( + "net/http" ++ "net/http/httptest" + "testing" + + "github.com/grafana/grafana/pkg/bus" +@@ -11,6 +12,7 @@ import ( + "github.com/grafana/grafana/pkg/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ++ macaron "gopkg.in/macaron.v1" + ) + + func TestPluginProxy(t *testing.T) { +@@ -148,6 +150,48 @@ func TestPluginProxy(t *testing.T) { + ) + assert.Equal(t, "https://example.com", req.URL.String()) + }) ++ ++ t.Run("When proxying a request should set expected response headers", func(t *testing.T) { ++ requestHandled := false ++ backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ++ w.WriteHeader(200) ++ _, _ = w.Write([]byte("I am the backend")) ++ requestHandled = true ++ })) ++ ++ responseRecorder := &closeNotifierResponseRecorder{ ++ ResponseRecorder: httptest.NewRecorder(), ++ } ++ responseWriter := macaron.NewResponseWriter("GET", responseRecorder) ++ ++ t.Cleanup(responseRecorder.Close) ++ t.Cleanup(backendServer.Close) ++ ++ route := &plugins.AppPluginRoute{ ++ Path: "/", ++ URL: backendServer.URL, ++ } ++ ++ ctx := &models.ReqContext{ ++ SignedInUser: &models.SignedInUser{}, ++ Context: &macaron.Context{ ++ Req: macaron.Request{ ++ Request: httptest.NewRequest("GET", "/", nil), ++ }, ++ Resp: responseWriter, ++ }, ++ } ++ proxy := NewApiPluginProxy(ctx, "", route, "", &setting.Cfg{}) ++ proxy.ServeHTTP(ctx.Resp, ctx.Req.Request) ++ ++ for { ++ if requestHandled { ++ break ++ } ++ } ++ ++ require.Equal(t, "sandbox", ctx.Resp.Header().Get("Content-Security-Policy")) ++ }) + } + + // getPluginProxiedRequest is a helper for easier setup of tests based on global config and ReqContext. +diff --git a/pkg/plugins/backendplugin/manager.go b/pkg/plugins/backendplugin/manager.go +index 600e5c40acb2b..cc0c902fb6cdf 100644 +--- a/pkg/plugins/backendplugin/manager.go ++++ b/pkg/plugins/backendplugin/manager.go +@@ -406,6 +406,7 @@ func flushStream(plugin Plugin, stream CallResourceClientResponseStream, w http. + } + } + ++ proxyutil.SetProxyResponseHeaders(w.Header()) + w.WriteHeader(resp.Status) + } + +diff --git a/pkg/plugins/backendplugin/manager_test.go b/pkg/plugins/backendplugin/manager_test.go +index daa648e156c7a..e6155a00d949b 100644 +--- a/pkg/plugins/backendplugin/manager_test.go ++++ b/pkg/plugins/backendplugin/manager_test.go +@@ -177,7 +177,8 @@ func TestManager(t *testing.T) { + t.Run("Call resource should return expected response", func(t *testing.T) { + ctx.plugin.CallResourceHandlerFunc = backend.CallResourceHandlerFunc(func(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { + return sender.Send(&backend.CallResourceResponse{ +- Status: http.StatusOK, ++ Status: http.StatusOK, ++ Headers: map[string][]string{}, + }) + }) + +@@ -186,7 +187,13 @@ func TestManager(t *testing.T) { + w := httptest.NewRecorder() + err = ctx.manager.callResourceInternal(w, req, backend.PluginContext{PluginID: testPluginID}) + require.NoError(t, err) ++ for { ++ if w.Flushed { ++ break ++ } ++ } + require.Equal(t, http.StatusOK, w.Code) ++ require.Equal(t, "sandbox", w.Header().Get("Content-Security-Policy")) + }) + }) + }) +diff --git a/pkg/util/proxyutil/proxyutil.go b/pkg/util/proxyutil/proxyutil.go +index d6e3572133370..3db22a1426ed1 100644 +--- a/pkg/util/proxyutil/proxyutil.go ++++ b/pkg/util/proxyutil/proxyutil.go +@@ -42,3 +42,9 @@ func ClearCookieHeader(req *http.Request, keepCookiesNames []string) { + req.AddCookie(c) + } + } ++ ++// SetProxyResponseHeaders sets proxy response headers. ++// Sets Content-Security-Policy: sandbox ++func SetProxyResponseHeaders(header http.Header) { ++ header.Set("Content-Security-Policy", "sandbox") ++} diff --git a/grafana.spec b/grafana.spec index 84f7cbc..0ee4189 100644 --- a/grafana.spec +++ b/grafana.spec @@ -7,7 +7,7 @@ Name: grafana Version: 7.5.11 -Release: 4 +Release: 5 Summary: Metrics dashboard and graph editor License: Apache 2.0 URL: https://grafana.org @@ -32,6 +32,8 @@ Patch6: 006-remove-unused-frontend-crypto.patch Patch7: 007-patch-unused-backend-crypto.patch Patch8: CVE-2021-43813.patch Patch9: CVE-2022-21673.patch +#https://github.com/grafana/grafana/commit/27726868b3d7c613844b55cd209ca93645c99b85 +Patch10: CVE-2022-21702.patch BuildRequires: git, systemd, golang @@ -402,6 +404,7 @@ rm -r plugins-bundled %patch7 -p1 %patch8 -p1 %patch9 -p1 +%patch10 -p1 # Set up build subdirs and links @@ -566,6 +569,9 @@ rm -r pkg/macaron %changelog +* Thu Mar 17 2022 yaoxin - 7.5.11-5 +- Fix CVE-2022-21702 + * Thu Jan 27 2022 wangkai 7.5.11-4 - Fix CVE-2022-21673 -- Gitee