diff options
Diffstat (limited to 'recipes-containers/kubernetes/kubernetes/CVE-2020-8559.patch')
-rw-r--r-- | recipes-containers/kubernetes/kubernetes/CVE-2020-8559.patch | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/recipes-containers/kubernetes/kubernetes/CVE-2020-8559.patch b/recipes-containers/kubernetes/kubernetes/CVE-2020-8559.patch new file mode 100644 index 00000000..f47826df --- /dev/null +++ b/recipes-containers/kubernetes/kubernetes/CVE-2020-8559.patch | |||
@@ -0,0 +1,148 @@ | |||
1 | From ba3ca4929ed3887c95f94fcf97610f3449446804 Mon Sep 17 00:00:00 2001 | ||
2 | From: Tim Allclair <tallclair@google.com> | ||
3 | Date: Wed, 17 Jun 2020 11:09:02 -0700 | ||
4 | Subject: [PATCH] Don't return proxied redirects to the client | ||
5 | |||
6 | CVE: CVE-2020-8559 | ||
7 | Upstream-Status: Backport [https://github.com/kubernetes/kubernetes.git branch:release-1.16] | ||
8 | Signed-off-by: Zhixiong Chi <zhixiong.chi@windriver.com> | ||
9 | --- | ||
10 | .../k8s.io/apimachinery/pkg/util/net/http.go | 2 +- | ||
11 | .../apimachinery/pkg/util/net/http_test.go | 12 ++--- | ||
12 | .../pkg/util/proxy/upgradeaware.go | 10 ++++ | ||
13 | .../pkg/util/proxy/upgradeaware_test.go | 47 ++++++++++++++++++- | ||
14 | 4 files changed, 62 insertions(+), 9 deletions(-) | ||
15 | |||
16 | diff --git a/src/import/staging/src/k8s.io/apimachinery/pkg/util/net/http.go b/src/import/staging/src/k8s.io/apimachinery/pkg/util/net/http.go | ||
17 | index bd79d6c4a09..c24fbc6921c 100644 | ||
18 | --- a/src/import/staging/src/k8s.io/apimachinery/pkg/util/net/http.go | ||
19 | +++ b/src/import/staging/src/k8s.io/apimachinery/pkg/util/net/http.go | ||
20 | @@ -431,7 +431,7 @@ redirectLoop: | ||
21 | |||
22 | // Only follow redirects to the same host. Otherwise, propagate the redirect response back. | ||
23 | if requireSameHostRedirects && location.Hostname() != originalLocation.Hostname() { | ||
24 | - break redirectLoop | ||
25 | + return nil, nil, fmt.Errorf("hostname mismatch: expected %s, found %s", originalLocation.Hostname(), location.Hostname()) | ||
26 | } | ||
27 | |||
28 | // Reset the connection. | ||
29 | diff --git a/src/import/staging/src/k8s.io/apimachinery/pkg/util/net/http_test.go b/src/import/staging/src/k8s.io/apimachinery/pkg/util/net/http_test.go | ||
30 | index 4e4e317b9a4..142b80f1a84 100644 | ||
31 | --- a/src/import/staging/src/k8s.io/apimachinery/pkg/util/net/http_test.go | ||
32 | +++ b/src/import/staging/src/k8s.io/apimachinery/pkg/util/net/http_test.go | ||
33 | @@ -330,13 +330,13 @@ func TestConnectWithRedirects(t *testing.T) { | ||
34 | redirects: []string{"/1", "/2", "/3", "/4", "/5", "/6", "/7", "/8", "/9", "/10"}, | ||
35 | expectError: true, | ||
36 | }, { | ||
37 | - desc: "redirect to different host are prevented", | ||
38 | - redirects: []string{"http://example.com/foo"}, | ||
39 | - expectedRedirects: 0, | ||
40 | + desc: "redirect to different host are prevented", | ||
41 | + redirects: []string{"http://example.com/foo"}, | ||
42 | + expectError: true, | ||
43 | }, { | ||
44 | - desc: "multiple redirect to different host forbidden", | ||
45 | - redirects: []string{"/1", "/2", "/3", "http://example.com/foo"}, | ||
46 | - expectedRedirects: 3, | ||
47 | + desc: "multiple redirect to different host forbidden", | ||
48 | + redirects: []string{"/1", "/2", "/3", "http://example.com/foo"}, | ||
49 | + expectError: true, | ||
50 | }, { | ||
51 | desc: "redirect to different port is allowed", | ||
52 | redirects: []string{"http://HOST/foo"}, | ||
53 | diff --git a/src/import/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go b/src/import/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go | ||
54 | index fcdc76a0529..3a02919d135 100644 | ||
55 | --- a/src/import/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go | ||
56 | +++ b/src/import/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go | ||
57 | @@ -298,6 +298,16 @@ func (h *UpgradeAwareHandler) tryUpgrade(w http.ResponseWriter, req *http.Reques | ||
58 | rawResponse = headerBytes | ||
59 | } | ||
60 | |||
61 | + // If the backend did not upgrade the request, return an error to the client. If the response was | ||
62 | + // an error, the error is forwarded directly after the connection is hijacked. Otherwise, just | ||
63 | + // return a generic error here. | ||
64 | + if backendHTTPResponse.StatusCode != http.StatusSwitchingProtocols && backendHTTPResponse.StatusCode < 400 { | ||
65 | + err := fmt.Errorf("invalid upgrade response: status code %d", backendHTTPResponse.StatusCode) | ||
66 | + klog.Errorf("Proxy upgrade error: %v", err) | ||
67 | + h.Responder.Error(w, req, err) | ||
68 | + return true | ||
69 | + } | ||
70 | + | ||
71 | // Once the connection is hijacked, the ErrorResponder will no longer work, so | ||
72 | // hijacking should be the last step in the upgrade. | ||
73 | requestHijacker, ok := w.(http.Hijacker) | ||
74 | diff --git a/src/import/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware_test.go b/src/import/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware_test.go | ||
75 | index 7d14f6534a8..236362373cd 100644 | ||
76 | --- a/src/import/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware_test.go | ||
77 | +++ b/src/import/staging/src/k8s.io/apimachinery/pkg/util/proxy/upgradeaware_test.go | ||
78 | @@ -493,7 +493,7 @@ func (r *noErrorsAllowed) Error(w http.ResponseWriter, req *http.Request, err er | ||
79 | r.t.Error(err) | ||
80 | } | ||
81 | |||
82 | -func TestProxyUpgradeErrorResponse(t *testing.T) { | ||
83 | +func TestProxyUpgradeConnectionErrorResponse(t *testing.T) { | ||
84 | var ( | ||
85 | responder *fakeResponder | ||
86 | expectedErr = errors.New("EXPECTED") | ||
87 | @@ -541,7 +541,7 @@ func TestProxyUpgradeErrorResponse(t *testing.T) { | ||
88 | |||
89 | func TestProxyUpgradeErrorResponseTerminates(t *testing.T) { | ||
90 | for _, intercept := range []bool{true, false} { | ||
91 | - for _, code := range []int{200, 400, 500} { | ||
92 | + for _, code := range []int{400, 500} { | ||
93 | t.Run(fmt.Sprintf("intercept=%v,code=%v", intercept, code), func(t *testing.T) { | ||
94 | // Set up a backend server | ||
95 | backend := http.NewServeMux() | ||
96 | @@ -601,6 +601,49 @@ func TestProxyUpgradeErrorResponseTerminates(t *testing.T) { | ||
97 | } | ||
98 | } | ||
99 | |||
100 | +func TestProxyUpgradeErrorResponse(t *testing.T) { | ||
101 | + for _, intercept := range []bool{true, false} { | ||
102 | + for _, code := range []int{200, 300, 302, 307} { | ||
103 | + t.Run(fmt.Sprintf("intercept=%v,code=%v", intercept, code), func(t *testing.T) { | ||
104 | + // Set up a backend server | ||
105 | + backend := http.NewServeMux() | ||
106 | + backend.Handle("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
107 | + http.Redirect(w, r, "https://example.com/there", code) | ||
108 | + })) | ||
109 | + backendServer := httptest.NewServer(backend) | ||
110 | + defer backendServer.Close() | ||
111 | + backendServerURL, _ := url.Parse(backendServer.URL) | ||
112 | + backendServerURL.Path = "/hello" | ||
113 | + | ||
114 | + // Set up a proxy pointing to a specific path on the backend | ||
115 | + proxyHandler := NewUpgradeAwareHandler(backendServerURL, nil, false, false, &fakeResponder{t: t}) | ||
116 | + proxyHandler.InterceptRedirects = intercept | ||
117 | + proxyHandler.RequireSameHostRedirects = true | ||
118 | + proxy := httptest.NewServer(proxyHandler) | ||
119 | + defer proxy.Close() | ||
120 | + proxyURL, _ := url.Parse(proxy.URL) | ||
121 | + | ||
122 | + conn, err := net.Dial("tcp", proxyURL.Host) | ||
123 | + require.NoError(t, err) | ||
124 | + bufferedReader := bufio.NewReader(conn) | ||
125 | + | ||
126 | + // Send upgrade request resulting in a non-101 response from the backend | ||
127 | + req, _ := http.NewRequest("GET", "/", nil) | ||
128 | + req.Header.Set(httpstream.HeaderConnection, httpstream.HeaderUpgrade) | ||
129 | + require.NoError(t, req.Write(conn)) | ||
130 | + // Verify we get the correct response and full message body content | ||
131 | + resp, err := http.ReadResponse(bufferedReader, nil) | ||
132 | + require.NoError(t, err) | ||
133 | + assert.Equal(t, fakeStatusCode, resp.StatusCode) | ||
134 | + resp.Body.Close() | ||
135 | + | ||
136 | + // clean up | ||
137 | + conn.Close() | ||
138 | + }) | ||
139 | + } | ||
140 | + } | ||
141 | +} | ||
142 | + | ||
143 | func TestDefaultProxyTransport(t *testing.T) { | ||
144 | tests := []struct { | ||
145 | name, | ||
146 | -- | ||
147 | 2.17.0 | ||
148 | |||