Package: squid3 / 3.4.8-6+deb8u5

43_Fix-CVE-2015-5400-regression.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
------------------------------------------------------------
revno: 13930
revision-id: squid3@treenet.co.nz-20150927082859-7za4czz7cpqry16n
parent: squid3@treenet.co.nz-20150927081853-u23ejmocr3694zyd
committer: Amos Jeffries <squid3@treenet.co.nz>
branch nick: 3.5
timestamp: Sun 2015-09-27 01:28:59 -0700
message:
  Fix cache_peer login=PASS(THRU) after CVE-2015-5400
  
  The patch for CVE-2015-5400 converts all non-200 peer responses
  into 502 Bad Gateway responses when relaying a CONNECT to a peer.
  
  This happens to break login=PASS and login=PASSTHRU behaviour
  which relies on the 401 and 407 status being relayed transparently.
  
  We need to relay the auth server responses as-is when login= is
  set to PASS or PASSTHRU but then unconditionally close the
  connections to prevent CVE-2015-5400 from occuring.
------------------------------------------------------------
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: squid3@treenet.co.nz-20150927082859-7za4czz7cpqry16n
# target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
# testament_sha1: 57d2ad15fd181cd054567c3028663f0f9eb07197
# timestamp: 2015-09-27 08:51:01 +0000
# source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
# base_revision_id: squid3@treenet.co.nz-20150927081853-\
#   u23ejmocr3694zyd
# 
# Begin patch
=== modified file 'src/tunnel.cc'
--- a/src/tunnel.cc
+++ b/src/tunnel.cc
@@ -124,7 +124,7 @@ public:
 
     /// Sends "502 Bad Gateway" error response to the client,
     /// if it is waiting for Squid CONNECT response, closing connections.
-    void informUserOfPeerError(const char *errMsg);
+    void informUserOfPeerError(const char *errMsg, size_t);
 
     class Connection
     {
@@ -351,20 +351,33 @@ TunnelStateData::readConnectResponseDone
 }
 
 void
-TunnelStateData::informUserOfPeerError(const char *errMsg)
+TunnelStateData::informUserOfPeerError(const char *errMsg, const size_t sz)
 {
     server.len = 0;
+
     if (!clientExpectsConnectResponse()) {
         // closing the connection is the best we can do here
         debugs(50, 3, server.conn << " closing on error: " << errMsg);
         server.conn->close();
         return;
     }
-    ErrorState *err  = new ErrorState(ERR_CONNECT_FAIL, Http::scBadGateway, request.getRaw());
-    err->callback = tunnelErrorComplete;
-    err->callback_data = this;
-    *status_ptr = Http::scBadGateway;
-    errorSend(http->getConn()->clientConnection, err);
+
+    // if we have no reply suitable to relay, use 502 Bad Gateway
+    if (!sz || sz > static_cast<size_t>(connectRespBuf->contentSize())) {
+        ErrorState *err = new ErrorState(ERR_CONNECT_FAIL, Http::scBadGateway, request.getRaw());
+        *status_ptr = Http::scBadGateway;
+        err->callback = tunnelErrorComplete;
+        err->callback_data = this;
+        errorSend(http->getConn()->clientConnection, err);
+        return;
+    }
+
+    // if we need to send back the server response. write its headers to the client
+    server.len = sz;
+    memcpy(server.buf, connectRespBuf->content(), server.len);
+    copy(server.len, server, client, TunnelStateData::WriteClientDone);
+    // then close the server FD to prevent any relayed keep-alive causing CVE-2015-5400
+    server.closeIfOpen();
 }
 
 /* Read from client side and queue it for writing to the server */
@@ -398,7 +411,7 @@ TunnelStateData::handleConnectResponse(c
     const bool parsed = rep.parse(connectRespBuf, eof, &parseErr);
     if (!parsed) {
         if (parseErr > 0) { // unrecoverable parsing error
-            informUserOfPeerError("malformed CONNECT response from peer");
+            informUserOfPeerError("malformed CONNECT response from peer", 0);
             return;
         }
 
@@ -407,7 +420,7 @@ TunnelStateData::handleConnectResponse(c
         assert(!parseErr);
 
         if (!connectRespBuf->hasSpace()) {
-            informUserOfPeerError("huge CONNECT response from peer");
+            informUserOfPeerError("huge CONNECT response from peer", 0);
             return;
         }
 
@@ -419,10 +432,16 @@ TunnelStateData::handleConnectResponse(c
     // CONNECT response was successfully parsed
     *status_ptr = rep.sline.status();
 
+    // we need to relay the 401/407 responses when login=PASS(THRU)
+    const char *pwd = server.conn->getPeer()->login;
+    const bool relay = pwd && (strcmp(pwd, "PASS") != 0 || strcmp(pwd, "PASSTHRU") != 0) &&
+                       (*status_ptr == Http::scProxyAuthenticationRequired ||
+                        *status_ptr == Http::scUnauthorized);
+
     // bail if we did not get an HTTP 200 (Connection Established) response
     if (rep.sline.status() != Http::scOkay) {
         // if we ever decide to reuse the peer connection, we must extract the error response first
-        informUserOfPeerError("unsupported CONNECT response status code");
+        informUserOfPeerError("unsupported CONNECT response status code", (relay ? rep.hdr_sz : 0));
         return;
     }