components/squid/patches/CVE-2015-5400.patch
changeset 5756 8233953c0160
equal deleted inserted replaced
5755:041717cfc591 5756:8233953c0160
       
     1 Fix for CVE-2015-5400. See:
       
     2 
       
     3   http://www.squid-cache.org/Advisories/SQUID-2015_2.txt
       
     4 
       
     5 for more details. Based on the squid version 3.5.X patch at:
       
     6 
       
     7   http://www.squid-cache.org/Versions/v3/3.5/changesets/squid-3.5-13856.patch
       
     8 
       
     9 --- squid-3.5.5/src/tunnel.cc.orig	2016-04-12 11:11:11.546364864 -0700
       
    10 +++ squid-3.5.5/src/tunnel.cc	2016-04-12 11:12:40.789271952 -0700
       
    11 @@ -110,6 +110,10 @@
       
    12                   (request->flags.interceptTproxy || request->flags.intercepted));
       
    13      }
       
    14  
       
    15 +    /// Sends "502 Bad Gateway" error response to the client,
       
    16 +    /// if it is waiting for Squid CONNECT response, closing connections.
       
    17 +    void informUserOfPeerError(const char *errMsg);
       
    18 +
       
    19      class Connection
       
    20      {
       
    21  
       
    22 @@ -128,12 +132,13 @@
       
    23  
       
    24          void error(int const xerrno);
       
    25          int debugLevelForError(int const xerrno) const;
       
    26 -        /// handles a non-I/O error associated with this Connection
       
    27 -        void logicError(const char *errMsg);
       
    28          void closeIfOpen();
       
    29          void dataSent (size_t amount);
       
    30 +        /// writes 'b' buffer, setting the 'writer' member to 'callback'.
       
    31 +        void write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func);
       
    32          int len;
       
    33          char *buf;
       
    34 +        AsyncCall::Pointer writer; ///< pending Comm::Write callback
       
    35          int64_t *size_ptr;      /* pointer to size in an ConnStateData for logging */
       
    36  
       
    37          Comm::ConnectionPointer conn;    ///< The currently connected connection.
       
    38 @@ -223,6 +228,7 @@
       
    39      TunnelStateData *tunnelState = (TunnelStateData *)params.data;
       
    40      debugs(26, 3, HERE << tunnelState->server.conn);
       
    41      tunnelState->server.conn = NULL;
       
    42 +    tunnelState->server.writer = NULL;
       
    43  
       
    44      if (tunnelState->request != NULL)
       
    45          tunnelState->request->hier.stopPeerClock(false);
       
    46 @@ -232,7 +238,7 @@
       
    47          return;
       
    48      }
       
    49  
       
    50 -    if (!tunnelState->server.len) {
       
    51 +    if (!tunnelState->client.writer) {
       
    52          tunnelState->client.conn->close();
       
    53          return;
       
    54      }
       
    55 @@ -244,13 +250,14 @@
       
    56      TunnelStateData *tunnelState = (TunnelStateData *)params.data;
       
    57      debugs(26, 3, HERE << tunnelState->client.conn);
       
    58      tunnelState->client.conn = NULL;
       
    59 +    tunnelState->client.writer = NULL;
       
    60  
       
    61      if (tunnelState->noConnections()) {
       
    62          delete tunnelState;
       
    63          return;
       
    64      }
       
    65  
       
    66 -    if (!tunnelState->client.len) {
       
    67 +    if (!tunnelState->server.writer) {
       
    68          tunnelState->server.conn->close();
       
    69          return;
       
    70      }
       
    71 @@ -381,6 +388,23 @@
       
    72          handleConnectResponse(len);
       
    73  }
       
    74  
       
    75 +void
       
    76 +TunnelStateData::informUserOfPeerError(const char *errMsg)
       
    77 +{
       
    78 +    server.len = 0;
       
    79 +    if (!clientExpectsConnectResponse()) {
       
    80 +        // closing the connection is the best we can do here
       
    81 +        debugs(50, 3, server.conn << " closing on error: " << errMsg);
       
    82 +        server.conn->close();
       
    83 +        return;
       
    84 +    }
       
    85 +    ErrorState *err  = new ErrorState(ERR_CONNECT_FAIL, Http::scBadGateway, request.getRaw());
       
    86 +    err->callback = tunnelErrorComplete;
       
    87 +    err->callback_data = this;
       
    88 +    *status_ptr = Http::scBadGateway;
       
    89 +    errorSend(http->getConn()->clientConnection, err);
       
    90 +}
       
    91 +
       
    92  /* Read from client side and queue it for writing to the server */
       
    93  void
       
    94  TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
       
    95 @@ -412,7 +436,7 @@
       
    96      const bool parsed = rep.parse(connectRespBuf, eof, &parseErr);
       
    97      if (!parsed) {
       
    98          if (parseErr > 0) { // unrecoverable parsing error
       
    99 -            server.logicError("malformed CONNECT response from peer");
       
   100 +            informUserOfPeerError("malformed CONNECT response from peer");
       
   101              return;
       
   102          }
       
   103  
       
   104 @@ -421,7 +445,7 @@
       
   105          assert(!parseErr);
       
   106  
       
   107          if (!connectRespBuf->hasSpace()) {
       
   108 -            server.logicError("huge CONNECT response from peer");
       
   109 +            informUserOfPeerError("huge CONNECT response from peer");
       
   110              return;
       
   111          }
       
   112  
       
   113 @@ -435,7 +459,8 @@
       
   114  
       
   115      // bail if we did not get an HTTP 200 (Connection Established) response
       
   116      if (rep.sline.status() != Http::scOkay) {
       
   117 -        server.logicError("unsupported CONNECT response status code");
       
   118 +        // if we ever decide to reuse the peer connection, we must extract the error response first
       
   119 +        informUserOfPeerError("unsupported CONNECT response status code");
       
   120          return;
       
   121      }
       
   122  
       
   123 @@ -454,13 +479,6 @@
       
   124  }
       
   125  
       
   126  void
       
   127 -TunnelStateData::Connection::logicError(const char *errMsg)
       
   128 -{
       
   129 -    debugs(50, 3, conn << " closing on error: " << errMsg);
       
   130 -    conn->close();
       
   131 -}
       
   132 -
       
   133 -void
       
   134  TunnelStateData::Connection::error(int const xerrno)
       
   135  {
       
   136      /* XXX fixme xstrerror and xerrno... */
       
   137 @@ -556,7 +574,7 @@
       
   138      debugs(26, 3, HERE << "Schedule Write");
       
   139      AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
       
   140                                           CommIoCbPtrFun(completion, this));
       
   141 -    Comm::Write(to.conn, from.buf, len, call, NULL);
       
   142 +    to.write(from.buf, len, call, NULL);
       
   143  }
       
   144  
       
   145  /* Writes data from the client buffer to the server side */
       
   146 @@ -565,6 +583,7 @@
       
   147  {
       
   148      TunnelStateData *tunnelState = (TunnelStateData *)data;
       
   149      assert (cbdataReferenceValid (tunnelState));
       
   150 +    tunnelState->server.writer = NULL;
       
   151  
       
   152      tunnelState->writeServerDone(buf, len, flag, xerrno);
       
   153  }
       
   154 @@ -614,6 +633,7 @@
       
   155  {
       
   156      TunnelStateData *tunnelState = (TunnelStateData *)data;
       
   157      assert (cbdataReferenceValid (tunnelState));
       
   158 +    tunnelState->client.writer = NULL;
       
   159  
       
   160      tunnelState->writeClientDone(buf, len, flag, xerrno);
       
   161  }
       
   162 @@ -631,7 +651,14 @@
       
   163  }
       
   164  
       
   165  void
       
   166 -TunnelStateData::writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
       
   167 +TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
       
   168 +{
       
   169 +    writer = callback;
       
   170 +    Comm::Write(conn, b, size, callback, free_func);
       
   171 +}
       
   172 +
       
   173 +void
       
   174 +TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
       
   175  {
       
   176      debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
       
   177  
       
   178 @@ -789,6 +816,7 @@
       
   179  {
       
   180      TunnelStateData *tunnelState = (TunnelStateData *)data;
       
   181      debugs(26, 3, HERE << conn << ", flag=" << flag);
       
   182 +    tunnelState->client.writer = NULL;
       
   183  
       
   184      if (flag != Comm::OK) {
       
   185          *tunnelState->status_ptr = Http::scInternalServerError;
       
   186 @@ -805,6 +833,7 @@
       
   187  {
       
   188      TunnelStateData *tunnelState = (TunnelStateData *)data;
       
   189      debugs(26, 3, conn << ", flag=" << flag);
       
   190 +    tunnelState->server.writer = NULL;
       
   191      assert(tunnelState->waitingForConnectRequest());
       
   192  
       
   193      if (flag != Comm::OK) {
       
   194 @@ -845,7 +874,7 @@
       
   195      else {
       
   196          AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
       
   197                                               CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
       
   198 -        Comm::Write(tunnelState->client.conn, conn_established, strlen(conn_established), call, NULL);
       
   199 +        tunnelState->client.write(conn_established, strlen(conn_established), call, NULL);
       
   200      }
       
   201  }
       
   202  
       
   203 @@ -1064,29 +1093,21 @@
       
   204      debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState->server.conn << ":\n----------\n" <<
       
   205             Raw("tunnelRelayConnectRequest", mb.content(), mb.contentSize()) << "\n----------");
       
   206  
       
   207 -    if (tunnelState->clientExpectsConnectResponse()) {
       
   208 -        // hack: blindly tunnel peer response (to our CONNECT request) to the client as ours.
       
   209 -        AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectedWriteDone",
       
   210 -                                       CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
       
   211 -        Comm::Write(srv, &mb, writeCall);
       
   212 -    } else {
       
   213 -        // we have to eat the connect response from the peer (so that the client
       
   214 -        // does not see it) and only then start shoveling data to the client
       
   215 -        AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectReqWriteDone",
       
   216 -                                       CommIoCbPtrFun(tunnelConnectReqWriteDone,
       
   217 -                                               tunnelState));
       
   218 -        Comm::Write(srv, &mb, writeCall);
       
   219 -        tunnelState->connectReqWriting = true;
       
   220 -
       
   221 -        tunnelState->connectRespBuf = new MemBuf;
       
   222 -        // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
       
   223 -        // can hold since any CONNECT response leftovers have to fit into server.buf.
       
   224 -        // 2*SQUID_TCP_SO_RCVBUF: HttpMsg::parse() zero-terminates, which uses space.
       
   225 -        tunnelState->connectRespBuf->init(SQUID_TCP_SO_RCVBUF, 2*SQUID_TCP_SO_RCVBUF);
       
   226 -        tunnelState->readConnectResponse();
       
   227 +    AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectReqWriteDone",
       
   228 +                                   CommIoCbPtrFun(tunnelConnectReqWriteDone,
       
   229 +                                           tunnelState));
       
   230 +
       
   231 +    tunnelState->server.write(mb.buf, mb.size, writeCall, mb.freeFunc());
       
   232 +    tunnelState->connectReqWriting = true;
       
   233 +
       
   234 +    tunnelState->connectRespBuf = new MemBuf;
       
   235 +    // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
       
   236 +    // can hold since any CONNECT response leftovers have to fit into server.buf.
       
   237 +    // 2*SQUID_TCP_SO_RCVBUF: HttpMsg::parse() zero-terminates, which uses space.
       
   238 +    tunnelState->connectRespBuf->init(SQUID_TCP_SO_RCVBUF, 2*SQUID_TCP_SO_RCVBUF);
       
   239 +    tunnelState->readConnectResponse();
       
   240  
       
   241 -        assert(tunnelState->waitingForConnectExchange());
       
   242 -    }
       
   243 +    assert(tunnelState->waitingForConnectExchange());
       
   244  
       
   245      AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
       
   246                                       CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
       
   247 @@ -1219,7 +1240,7 @@
       
   248  
       
   249      AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
       
   250                                           CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
       
   251 -    Comm::Write(tunnelState->client.conn, buf.content(), buf.contentSize(), call, NULL);
       
   252 +    tunnelState->client.write(buf.content(), buf.contentSize(), call, NULL);
       
   253  }
       
   254  #endif //USE_OPENSSL
       
   255