diff options
Diffstat (limited to 'meta-networking/recipes-daemons/squid/files/CVE-2015-5400.patch')
-rw-r--r-- | meta-networking/recipes-daemons/squid/files/CVE-2015-5400.patch | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/meta-networking/recipes-daemons/squid/files/CVE-2015-5400.patch b/meta-networking/recipes-daemons/squid/files/CVE-2015-5400.patch new file mode 100644 index 0000000000..41af2b1017 --- /dev/null +++ b/meta-networking/recipes-daemons/squid/files/CVE-2015-5400.patch @@ -0,0 +1,292 @@ +Fix: CVE-2015-5400 + +------------------------------------------------------------ +revno: 13225 +revision-id: squid3@treenet.co.nz-20150709032133-qg1patn5zngt4o4h +parent: squid3@treenet.co.nz-20150501100500-3utkhrao1yrd8ig6 +author: Alex Rousskov <rousskov@measurement-factory.com> +committer: Amos Jeffries <squid3@treenet.co.nz> +branch nick: 3.4 +timestamp: Wed 2015-07-08 20:21:33 -0700 +message: + Do not blindly forward cache peer CONNECT responses. + + Squid blindly forwards cache peer CONNECT responses to clients. This + may break things if the peer responds with something like HTTP 403 + (Forbidden) and keeps the connection with Squid open: + - The client application issues a CONNECT request. + - Squid forwards this request to a cache peer. + - Cache peer correctly responds back with a "403 Forbidden". + - Squid does not parse cache peer response and + just forwards it as if it was a Squid response to the client. + - The TCP connections are not closed. + + At this stage, Squid is unaware that the CONNECT request has failed. All + subsequent requests on the user agent TCP connection are treated as + tunnelled traffic. Squid is forwarding these requests to the peer on the + TCP connection previously used for the 403-ed CONNECT request, without + proper processing. The additional headers which should have been applied + by Squid to these requests are not applied, and the requests are being + forwarded to the cache peer even though the Squid configuration may + state that these requests must go directly to the origin server. + + This fixes Squid to parse cache peer responses, and if an error response + found, respond with "502 Bad Gateway" to the client and close the + connections. +------------------------------------------------------------ +# Bazaar merge directive format 2 (Bazaar 0.90) +# revision_id: squid3@treenet.co.nz-20150709032133-qg1patn5zngt4o4h +# target_branch: http://bzr.squid-cache.org/bzr/squid3/3.4 +# testament_sha1: 6cbce093f30c8a09173eb610eaa423c7c305ff23 +# timestamp: 2015-07-09 03:40:35 +0000 +# source_branch: http://bzr.squid-cache.org/bzr/squid3/3.4 +# base_revision_id: squid3@treenet.co.nz-20150501100500-\ +# 3utkhrao1yrd8ig6 +# +# Begin patch + +Upstream-Status: Backport +http://www.squid-cache.org/Versions/v3/3.4/changesets/squid-3.4-13225.patch + +Signed-off-by: Armin Kuster <akuster@mvista.com> + +=== modified file 'src/tunnel.cc' +--- a/src/tunnel.cc 2014-04-26 10:58:22 +0000 ++++ b/src/tunnel.cc 2015-07-09 03:21:33 +0000 +@@ -122,6 +122,10 @@ + (request->flags.interceptTproxy || request->flags.intercepted)); + } + ++ /// Sends "502 Bad Gateway" error response to the client, ++ /// if it is waiting for Squid CONNECT response, closing connections. ++ void informUserOfPeerError(const char *errMsg); ++ + class Connection + { + +@@ -139,13 +143,14 @@ + + void error(int const xerrno); + int debugLevelForError(int const xerrno) const; +- /// handles a non-I/O error associated with this Connection +- void logicError(const char *errMsg); + void closeIfOpen(); + void dataSent (size_t amount); ++ /// writes 'b' buffer, setting the 'writer' member to 'callback'. ++ void write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func); + int len; + char *buf; + int64_t *size_ptr; /* pointer to size in an ConnStateData for logging */ ++ AsyncCall::Pointer writer; ///< pending Comm::Write callback + + Comm::ConnectionPointer conn; ///< The currently connected connection. + +@@ -195,13 +200,14 @@ + TunnelStateData *tunnelState = (TunnelStateData *)params.data; + debugs(26, 3, HERE << tunnelState->server.conn); + tunnelState->server.conn = NULL; ++ tunnelState->server.writer = NULL; + + if (tunnelState->noConnections()) { + delete tunnelState; + return; + } + +- if (!tunnelState->server.len) { ++ if (!tunnelState->client.writer) { + tunnelState->client.conn->close(); + return; + } +@@ -213,13 +219,14 @@ + TunnelStateData *tunnelState = (TunnelStateData *)params.data; + debugs(26, 3, HERE << tunnelState->client.conn); + tunnelState->client.conn = NULL; ++ tunnelState->client.writer = NULL; + + if (tunnelState->noConnections()) { + delete tunnelState; + return; + } + +- if (!tunnelState->client.len) { ++ if (!tunnelState->server.writer) { + tunnelState->server.conn->close(); + return; + } +@@ -343,6 +350,23 @@ + handleConnectResponse(len); + } + ++void ++TunnelStateData::informUserOfPeerError(const char *errMsg) ++{ ++ 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); ++} ++ + /* Read from client side and queue it for writing to the server */ + void + TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data) +@@ -374,7 +398,7 @@ + const bool parsed = rep.parse(connectRespBuf, eof, &parseErr); + if (!parsed) { + if (parseErr > 0) { // unrecoverable parsing error +- server.logicError("malformed CONNECT response from peer"); ++ informUserOfPeerError("malformed CONNECT response from peer"); + return; + } + +@@ -383,7 +407,7 @@ + assert(!parseErr); + + if (!connectRespBuf->hasSpace()) { +- server.logicError("huge CONNECT response from peer"); ++ informUserOfPeerError("huge CONNECT response from peer"); + return; + } + +@@ -397,7 +421,8 @@ + + // bail if we did not get an HTTP 200 (Connection Established) response + if (rep.sline.status() != Http::scOkay) { +- server.logicError("unsupported CONNECT response status code"); ++ // if we ever decide to reuse the peer connection, we must extract the error response first ++ informUserOfPeerError("unsupported CONNECT response status code"); + return; + } + +@@ -416,13 +441,6 @@ + } + + void +-TunnelStateData::Connection::logicError(const char *errMsg) +-{ +- debugs(50, 3, conn << " closing on error: " << errMsg); +- conn->close(); +-} +- +-void + TunnelStateData::Connection::error(int const xerrno) + { + /* XXX fixme xstrerror and xerrno... */ +@@ -517,7 +535,7 @@ + debugs(26, 3, HERE << "Schedule Write"); + AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler", + CommIoCbPtrFun(completion, this)); +- Comm::Write(to.conn, from.buf, len, call, NULL); ++ to.write(from.buf, len, call, NULL); + } + + /* Writes data from the client buffer to the server side */ +@@ -526,6 +544,7 @@ + { + TunnelStateData *tunnelState = (TunnelStateData *)data; + assert (cbdataReferenceValid (tunnelState)); ++ tunnelState->server.writer = NULL; + + tunnelState->writeServerDone(buf, len, flag, xerrno); + } +@@ -575,6 +594,7 @@ + { + TunnelStateData *tunnelState = (TunnelStateData *)data; + assert (cbdataReferenceValid (tunnelState)); ++ tunnelState->client.writer = NULL; + + tunnelState->writeClientDone(buf, len, flag, xerrno); + } +@@ -592,7 +612,14 @@ + } + + void +-TunnelStateData::writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno) ++TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func) ++{ ++ writer = callback; ++ Comm::Write(conn, b, size, callback, free_func); ++} ++ ++void ++TunnelStateData::writeClientDone(char *, size_t len, comm_err_t flag, int xerrno) + { + debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag); + +@@ -712,6 +739,7 @@ + { + TunnelStateData *tunnelState = (TunnelStateData *)data; + debugs(26, 3, HERE << conn << ", flag=" << flag); ++ tunnelState->client.writer = NULL; + + if (flag != COMM_OK) { + *tunnelState->status_ptr = Http::scInternalServerError; +@@ -728,6 +756,7 @@ + { + TunnelStateData *tunnelState = (TunnelStateData *)data; + debugs(26, 3, conn << ", flag=" << flag); ++ tunnelState->server.writer = NULL; + assert(tunnelState->waitingForConnectRequest()); + + if (flag != COMM_OK) { +@@ -768,7 +797,7 @@ + else { + AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone", + CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState)); +- Comm::Write(tunnelState->client.conn, conn_established, strlen(conn_established), call, NULL); ++ tunnelState->client.write(conn_established, strlen(conn_established), call, NULL); + } + } + +@@ -955,29 +984,20 @@ + debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState->server.conn << ":\n----------\n" << + Raw("tunnelRelayConnectRequest", mb.content(), mb.contentSize()) << "\n----------"); + +- if (tunnelState->clientExpectsConnectResponse()) { +- // hack: blindly tunnel peer response (to our CONNECT request) to the client as ours. +- AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectedWriteDone", +- CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState)); +- Comm::Write(srv, &mb, writeCall); +- } else { +- // we have to eat the connect response from the peer (so that the client +- // does not see it) and only then start shoveling data to the client +- AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectReqWriteDone", +- CommIoCbPtrFun(tunnelConnectReqWriteDone, +- tunnelState)); +- Comm::Write(srv, &mb, writeCall); +- tunnelState->connectReqWriting = true; +- +- tunnelState->connectRespBuf = new MemBuf; +- // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer +- // can hold since any CONNECT response leftovers have to fit into server.buf. +- // 2*SQUID_TCP_SO_RCVBUF: HttpMsg::parse() zero-terminates, which uses space. +- tunnelState->connectRespBuf->init(SQUID_TCP_SO_RCVBUF, 2*SQUID_TCP_SO_RCVBUF); +- tunnelState->readConnectResponse(); +- +- assert(tunnelState->waitingForConnectExchange()); +- } ++ AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectReqWriteDone", ++ CommIoCbPtrFun(tunnelConnectReqWriteDone, tunnelState)); ++ ++ tunnelState->server.write(mb.buf, mb.size, writeCall, mb.freeFunc()); ++ tunnelState->connectReqWriting = true; ++ ++ tunnelState->connectRespBuf = new MemBuf; ++ // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer ++ // can hold since any CONNECT response leftovers have to fit into server.buf. ++ // 2*SQUID_TCP_SO_RCVBUF: HttpMsg::parse() zero-terminates, which uses space. ++ tunnelState->connectRespBuf->init(SQUID_TCP_SO_RCVBUF, 2*SQUID_TCP_SO_RCVBUF); ++ tunnelState->readConnectResponse(); ++ ++ assert(tunnelState->waitingForConnectExchange()); + + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", + CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); + |