]> granicus.if.org Git - php/commitdiff
Bug #41631: Observe socket read timeouts in SSL streams
authorDaniel Lowrey <rdlowrey@php.net>
Thu, 7 Aug 2014 15:47:42 +0000 (11:47 -0400)
committerDaniel Lowrey <rdlowrey@php.net>
Thu, 7 Aug 2014 15:47:42 +0000 (11:47 -0400)
ext/openssl/xp_ssl.c

index 3082c839d9ea4ed9693d6f2a76d952cfbd2b39aa..672070e19da02b38371f8771b3d9d55aa43b9a66 100644 (file)
@@ -204,13 +204,59 @@ static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size
        return didwrite;
 }
 
+static void php_openssl_stream_wait_for_data(php_netstream_data_t *sock TSRMLS_DC)
+{
+       int retval;
+       struct timeval *ptimeout;
+
+       if (sock->socket == -1) {
+               return;
+       }
+       
+       sock->timeout_event = 0;
+
+       if (sock->timeout.tv_sec == -1)
+               ptimeout = NULL;
+       else
+               ptimeout = &sock->timeout;
+
+       while(1) {
+               retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout);
+
+               if (retval == 0)
+                       sock->timeout_event = 1;
+
+               if (retval >= 0)
+                       break;
+
+               if (php_socket_errno() != EINTR)
+                       break;
+       }
+}
+
 static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
 {
        php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
+       php_netstream_data_t *sock;
        int nr_bytes = 0;
 
        if (sslsock->ssl_active) {
                int retry = 1;
+               sock = (php_netstream_data_t*)stream->abstract;
+
+               /* The SSL_read() function will block indefinitely waiting for data on a blocking
+                  socket. If we don't poll for readability first this operation has the potential
+                  to hang forever. To avoid this scenario we poll with a timeout before performing
+                  the actual read. If it times out we're finished.
+               */
+               if (sock->is_blocked) {
+                       php_openssl_stream_wait_for_data(sock);
+                       if (sock->timeout_event) {
+                               stream->eof = 1;
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL read operation timed out");
+                               return nr_bytes;
+                       }
+               }
 
                do {
                        nr_bytes = SSL_read(sslsock->ssl_handle, buf, count);