]> granicus.if.org Git - php/commitdiff
Fix stream_select() issue with OpenSSL buffer
authorChris Wright <github@daverandom.com>
Sat, 23 Aug 2014 00:40:19 +0000 (01:40 +0100)
committerDaniel Lowrey <rdlowrey@php.net>
Fri, 6 Mar 2015 00:18:14 +0000 (17:18 -0700)
Ensure data from OpenSSL internal buffer has been
transfered to PHP stream buffer before a select()
emulation operation is performed

Addresses bug #65137
https://bugs.php.net/bug.php?id=65137

Conflicts:
ext/openssl/xp_ssl.c

NEWS
ext/openssl/xp_ssl.c
main/php_streams.h
main/streams/streams.c

diff --git a/NEWS b/NEWS
index 0f3893c8e16c14561d55788f5d7dc612b42bdf95..290e3422b998ffcf62b071d591e35504c5c9c8be 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? Apr 2015, PHP 5.6.8
 
+- OpenSSL
+  . Fixed bugs #68853, #65137 (Buffered crypto stream data breaks IO polling
+    in stream_select() contexts) (Chris Wright)
+
 19 Mar 2015, PHP 5.6.7
 
 - Core:
index d04b3161b29fd6c3d5985376af70fd0d1b8dadda..ccc5af7df7642bce82d3b96ae60be8a654664cc5 100644 (file)
@@ -2276,7 +2276,20 @@ static int php_openssl_sockop_cast(php_stream *stream, int castas, void **ret TS
 
                case PHP_STREAM_AS_FD_FOR_SELECT:
                        if (ret) {
-                               *(php_socket_t *)ret = sslsock->s.socket;
+                               if (sslsock->ssl_active) {
+                                       /* OpenSSL has an internal buffer which select() cannot see. If we don't
+                                          fetch it into the stream's buffer, no activity will be reported on the
+                                          stream even though there is data waiting to be read - but we only fetch
+                                          the number of bytes OpenSSL has ready to give us since we weren't asked
+                                          for any data at this stage. This is only likely to cause issues with
+                                          non-blocking streams, but it's harmless to always do it. */
+                                       int bytes;
+                                       while ((bytes = SSL_pending(sslsock->ssl_handle)) > 0) {
+                                               php_stream_fill_read_buffer(stream, (size_t)bytes);
+                                       }
+                               }
+
+                               *(int *)ret = sslsock->s.socket;
                        }
                        return SUCCESS;
 
index 3fcab199f5894aeb72b9057a5b21007a361cfc7a..4da2dce98ef4d59ea8193119844eedd286fa9bf1 100644 (file)
@@ -297,6 +297,9 @@ PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t coun
 #define php_stream_write_string(stream, str)   _php_stream_write(stream, str, strlen(str) TSRMLS_CC)
 #define php_stream_write(stream, buf, count)   _php_stream_write(stream, (buf), (count) TSRMLS_CC)
 
+PHPAPI void _php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_DC);
+#define php_stream_fill_read_buffer(stream, size)      _php_stream_fill_read_buffer((stream), (size) TSRMLS_CC)
+
 #ifdef ZTS
 PHPAPI size_t _php_stream_printf(php_stream *stream TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
 #else
index e2e9e4947f4e35a9f7c3cbeb2504ffcc2a1e9cff..90fc505185600c5d8edb96c245d007e8730671f6 100644 (file)
@@ -568,7 +568,7 @@ fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remov
 
 /* {{{ generic stream operations */
 
-static void php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_DC)
+PHPAPI void _php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_DC)
 {
        /* allocate/fill the buffer */
 
@@ -736,7 +736,7 @@ PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS
                                break;
                        }
                } else {
-                       php_stream_fill_read_buffer(stream, size TSRMLS_CC);
+                       php_stream_fill_read_buffer(stream, size);
 
                        toread = stream->writepos - stream->readpos;
                        if (toread > size) {
@@ -972,7 +972,7 @@ PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen,
                                }
                        }
 
-                       php_stream_fill_read_buffer(stream, toread TSRMLS_CC);
+                       php_stream_fill_read_buffer(stream, toread);
 
                        if (stream->writepos - stream->readpos == 0) {
                                break;
@@ -1047,7 +1047,7 @@ PHPAPI char *php_stream_get_record(php_stream *stream, size_t maxlen, size_t *re
 
                to_read_now = MIN(maxlen - buffered_len, stream->chunk_size);
 
-               php_stream_fill_read_buffer(stream, buffered_len + to_read_now TSRMLS_CC);
+               php_stream_fill_read_buffer(stream, buffered_len + to_read_now);
 
                just_read = STREAM_BUFFERED_AMOUNT(stream) - buffered_len;