From 417ed16d11d2d7376b1a74028c42cd87818bfffb Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 7 Aug 2014 15:55:37 +0400 Subject: [PATCH] Make stream->context indirect trough zend_resource (stream->ctx->ptr). Fixed ext/standard/tests/streams/bug61115.phpt --- ext/openssl/xp_ssl.c | 56 +++++++++++++++---------------- ext/standard/http_fopen_wrapper.c | 2 +- ext/standard/streamsfuncs.c | 7 ++-- main/php_streams.h | 5 ++- main/streams/streams.c | 17 +++++----- main/streams/transports.c | 2 +- main/streams/xp_socket.c | 12 +++---- 7 files changed, 53 insertions(+), 48 deletions(-) diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 7c7ba235d9..c36a6432ee 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -67,7 +67,7 @@ #define STREAM_CRYPTO_METHOD_TLSv1_2 (1<<5) /* Simplify ssl context option retrieval */ -#define GET_VER_OPT(name) (stream->context && (val = php_stream_context_get_option(stream->context, "ssl", name)) != NULL) +#define GET_VER_OPT(name) (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", name)) != NULL) #define GET_VER_OPT_STRING(name, str) if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_P(val); } #define GET_VER_OPT_LONG(name, num) if (GET_VER_OPT(name)) { convert_to_long_ex(val); num = Z_LVAL_P(val); } @@ -985,7 +985,7 @@ static void limit_handshake_reneg(const SSL *ssl) /* {{{ */ sslsock->reneg->should_close = 1; - if (stream->context && (val = php_stream_context_get_option(stream->context, + if (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "reneg_limit_callback")) != NULL ) { zval param, retval; @@ -1028,8 +1028,8 @@ static void init_server_reneg_limit(php_stream *stream, php_openssl_netstream_da long limit = OPENSSL_DEFAULT_RENEG_LIMIT; long window = OPENSSL_DEFAULT_RENEG_WINDOW; - if (stream->context && - NULL != (val = php_stream_context_get_option(stream->context, + if (PHP_STREAM_CONTEXT(stream) && + NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "reneg_limit")) ) { convert_to_long(val); @@ -1041,8 +1041,8 @@ static void init_server_reneg_limit(php_stream *stream, php_openssl_netstream_da return; } - if (stream->context && - NULL != (val = php_stream_context_get_option(stream->context, + if (PHP_STREAM_CONTEXT(stream) && + NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "reneg_window")) ) { convert_to_long(val); @@ -1069,7 +1069,7 @@ static int set_server_rsa_key(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) /* {{{ int rsa_key_size; RSA* rsa; - if ((val = php_stream_context_get_option(stream->context, "ssl", "rsa_key_size")) != NULL) { + if ((val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "rsa_key_size")) != NULL) { rsa_key_size = (int) Z_LVAL_P(val); if ((rsa_key_size != 1) && (rsa_key_size & (rsa_key_size - 1))) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "RSA key size requires a power of 2: %d", rsa_key_size); @@ -1133,7 +1133,7 @@ static int set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) /* char *curve_str; EC_KEY *ecdh; - if ((val = php_stream_context_get_option(stream->context, "ssl", "ecdh_curve")) != NULL) { + if ((val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "ecdh_curve")) != NULL) { convert_to_string_ex(val); curve_str = Z_STRVAL_P(val); curve_nid = OBJ_sn2nid(curve_str); @@ -1171,7 +1171,7 @@ static int set_server_specific_opts(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) return FAILURE; } #else - if (SUCCESS == php_stream_context_get_option(stream->context, "ssl", "ecdh_curve", &val)) { + if (SUCCESS == php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "ecdh_curve", &val)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "ECDH curve support not compiled into the OpenSSL lib against which PHP is linked"); @@ -1179,7 +1179,7 @@ static int set_server_specific_opts(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) } #endif - if ((val = php_stream_context_get_option(stream->context, "ssl", "dh_param")) != NULL) { + if ((val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "dh_param")) != NULL) { convert_to_string_ex(val); if (FAILURE == set_server_dh_param(ctx, Z_STRVAL_P(val) TSRMLS_CC)) { return FAILURE; @@ -1191,14 +1191,14 @@ static int set_server_specific_opts(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) } if (NULL != (val = php_stream_context_get_option( - stream->context, "ssl", "honor_cipher_order")) && + PHP_STREAM_CONTEXT(stream), "ssl", "honor_cipher_order")) && zend_is_true(val TSRMLS_CC) ) { ssl_ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE; } if (NULL != (val = php_stream_context_get_option( - stream->context, "ssl", "single_dh_use")) && + PHP_STREAM_CONTEXT(stream), "ssl", "single_dh_use")) && zend_is_true(val TSRMLS_CC) ) { ssl_ctx_options |= SSL_OP_SINGLE_DH_USE; @@ -1206,7 +1206,7 @@ static int set_server_specific_opts(php_stream *stream, SSL_CTX *ctx TSRMLS_DC) #ifdef HAVE_ECDH if (NULL != (val = php_stream_context_get_option( - stream->context, "ssl", "single_ecdh_use")) && + PHP_STREAM_CONTEXT(stream), "ssl", "single_ecdh_use")) && zend_is_true(val TSRMLS_CC)) { ssl_ctx_options |= SSL_OP_SINGLE_ECDH_USE; } @@ -1460,7 +1460,7 @@ int php_openssl_setup_crypto(php_stream *stream, SSL_CTX_set_options(sslsock->ctx, ssl_ctx_options); if (sslsock->is_client == 0 && - stream->context && + PHP_STREAM_CONTEXT(stream) && FAILURE == set_server_specific_opts(stream, sslsock->ctx TSRMLS_CC) ) { return FAILURE; @@ -1546,16 +1546,16 @@ static int capture_peer_certs(php_stream *stream, php_openssl_netstream_data_t * zval *val, zcert; int cert_captured = 0; - if (NULL != (val = php_stream_context_get_option(stream->context, + if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "capture_peer_cert")) && zend_is_true(val TSRMLS_CC) ) { zend_register_resource(&zcert, peer_cert, php_openssl_get_x509_list_id() TSRMLS_CC); - php_stream_context_set_option(stream->context, "ssl", "peer_certificate", &zcert); + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_certificate", &zcert); cert_captured = 1; } - if (NULL != (val = php_stream_context_get_option(stream->context, + if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "capture_peer_cert_chain")) && zend_is_true(val TSRMLS_CC) ) { @@ -1578,7 +1578,7 @@ static int capture_peer_certs(php_stream *stream, php_openssl_netstream_data_t * ZVAL_NULL(&arr); } - php_stream_context_set_option(stream->context, "ssl", "peer_certificate_chain", &arr); + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_certificate_chain", &arr); zval_dtor(&arr); } @@ -1686,7 +1686,7 @@ static int php_openssl_enable_crypto(php_stream *stream, if (n == 1) { peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle); - if (peer_cert && stream->context) { + if (peer_cert && PHP_STREAM_CONTEXT(stream)) { cert_captured = capture_peer_certs(stream, sslsock, peer_cert TSRMLS_CC); } @@ -1696,16 +1696,16 @@ static int php_openssl_enable_crypto(php_stream *stream, } else { sslsock->ssl_active = 1; - if (stream->context) { + if (PHP_STREAM_CONTEXT(stream)) { zval *val; - if (NULL != (val = php_stream_context_get_option(stream->context, + if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "capture_session_meta")) && zend_is_true(val TSRMLS_CC) ) { zval meta_arr; ZVAL_ARR(&meta_arr, capture_session_meta(sslsock->ssl_handle)); - php_stream_context_set_option(stream->context, "ssl", "session_meta", &meta_arr); + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "session_meta", &meta_arr); zval_dtor(&meta_arr); } } @@ -1715,7 +1715,7 @@ static int php_openssl_enable_crypto(php_stream *stream, } else { n = -1; peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle); - if (peer_cert && stream->context) { + if (peer_cert && PHP_STREAM_CONTEXT(stream)) { cert_captured = capture_peer_certs(stream, sslsock, peer_cert TSRMLS_CC); } } @@ -1754,7 +1754,7 @@ static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size } while(retry); if (didwrite > 0) { - php_stream_notify_progress_increment(stream->context, didwrite, 0); + php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), didwrite, 0); } } else { didwrite = php_stream_socket_ops.write(stream, buf, count TSRMLS_CC); @@ -1796,7 +1796,7 @@ static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t coun } while (retry); if (nr_bytes > 0) { - php_stream_notify_progress_increment(stream->context, nr_bytes, 0); + php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0); } } else @@ -1926,9 +1926,9 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_ xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+"); if (xparam->outputs.client) { - xparam->outputs.client->context = stream->context; - if (stream->context) { - stream->context->res->gc.refcount++; + xparam->outputs.client->ctx = stream->ctx; + if (stream->ctx) { + GC_REFCOUNT(stream->ctx)++; } } } diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index d8f31960cc..1007b16123 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -229,7 +229,7 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, /* Set peer_name or name verification will try to use the proxy server name */ if (!context || (tmpzval = php_stream_context_get_option(context, "ssl", "peer_name")) == NULL) { ZVAL_STRING(&ssl_proxy_peer_name, resource->host); - php_stream_context_set_option(stream->context, "ssl", "peer_name", &ssl_proxy_peer_name); + php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_name", &ssl_proxy_peer_name); } smart_str_appendl(&header, "CONNECT ", sizeof("CONNECT ")-1); diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index fe51f48d52..9ba10edb13 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -40,7 +40,7 @@ typedef unsigned long long php_timeout_ull; typedef unsigned __int64 php_timeout_ull; #endif -#define GET_CTX_OPT(stream, wrapper, name, val) (stream->context && NULL != (val = php_stream_context_get_option(stream->context, wrapper, name))) +#define GET_CTX_OPT(stream, wrapper, name, val) (PHP_STREAM_CONTEXT(stream) && NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), wrapper, name))) static php_stream_context *decode_context_param(zval *contextresource TSRMLS_DC); @@ -939,13 +939,14 @@ static php_stream_context *decode_context_param(zval *contextresource TSRMLS_DC) stream = zend_fetch_resource(contextresource TSRMLS_CC, -1, NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream); if (stream) { - context = stream->context; + context = PHP_STREAM_CONTEXT(stream); if (context == NULL) { /* Only way this happens is if file is opened with NO_DEFAULT_CONTEXT param, but then something is called which requires a context. Don't give them the default one though since they already said they didn't want it. */ - context = stream->context = php_stream_context_alloc(TSRMLS_C); + context = php_stream_context_alloc(TSRMLS_C); + stream->ctx = context->res; } } } diff --git a/main/php_streams.h b/main/php_streams.h index fac15ce3e4..38215a67b0 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -205,7 +205,7 @@ struct _php_stream { int __exposed; /* non-zero if exposed as a zval somewhere */ char *orig_path; - php_stream_context *context; + zend_resource *ctx; int flags; /* PHP_STREAM_FLAG_XXX */ /* buffer */ @@ -228,6 +228,9 @@ struct _php_stream { struct _php_stream *enclosing_stream; /* this is a private stream owned by enclosing_stream */ }; /* php_stream */ +#define PHP_STREAM_CONTEXT(stream) \ + ((php_stream_context*) ((stream)->ctx ? ((stream)->ctx->ptr) : NULL)) + /* state definitions when closing down; these are private to streams.c */ #define PHP_STREAM_FCLOSE_NONE 0 #define PHP_STREAM_FCLOSE_FDOPEN 1 diff --git a/main/streams/streams.c b/main/streams/streams.c index 648a0d8c6d..89537bdaeb 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -91,11 +91,11 @@ fprintf(stderr, "forget_persistent: %s:%p\n", stream->ops->label, stream); stream->res = NULL; - if (stream->context) { + if (PHP_STREAM_CONTEXT(stream)) { zend_hash_apply_with_argument(&EG(regular_list), _php_stream_release_context, - stream->context TSRMLS_CC); - stream->context = NULL; + PHP_STREAM_CONTEXT(stream) TSRMLS_CC); + stream->ctx = NULL; } return 0; @@ -333,7 +333,7 @@ fprintf(stderr, "stream_alloc: %s:%p persistent=%s\n", ops->label, ret, persiste ZVAL_UNDEF(&ret->wrapperdata); ret->stdiocast = NULL; ret->orig_path = NULL; - ret->context = NULL; + ret->ctx = NULL; ret->readbuf = NULL; ret->enclosing_stream = NULL; @@ -387,7 +387,7 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* * already been freed (if it was created after the stream resource), so * don't reference it */ if (EG(active)) { - context = stream->context; + context = PHP_STREAM_CONTEXT(stream); } if (stream->flags & PHP_STREAM_FLAG_NO_CLOSE) { @@ -2167,12 +2167,13 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod /* {{{ context API */ PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context TSRMLS_DC) { - php_stream_context *oldcontext = stream->context; - - stream->context = context; + php_stream_context *oldcontext = PHP_STREAM_CONTEXT(stream); if (context) { + stream->ctx = context->res; GC_REFCOUNT(context->res)++; + } else { + stream->ctx = NULL; } if (oldcontext) { zend_list_delete(oldcontext->res); diff --git a/main/streams/transports.c b/main/streams/transports.c index 4f4832df2d..0db04cd495 100644 --- a/main/streams/transports.c +++ b/main/streams/transports.c @@ -160,7 +160,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in zval *zbacklog = NULL; int backlog = 32; - if (stream->context && (zbacklog = php_stream_context_get_option(stream->context, "socket", "backlog")) != NULL) { + if (PHP_STREAM_CONTEXT(stream) && (zbacklog = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "backlog")) != NULL) { zval *ztmp = zbacklog; convert_to_long_ex(ztmp); diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index b4799d48a8..34ffec883a 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -101,7 +101,7 @@ retry: } if (didwrite > 0) { - php_stream_notify_progress_increment(stream->context, didwrite, 0); + php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), didwrite, 0); } if (didwrite < 0) { @@ -161,7 +161,7 @@ static size_t php_sockop_read(php_stream *stream, char *buf, size_t count TSRMLS stream->eof = (nr_bytes == 0 || (nr_bytes == -1 && php_socket_errno() != EWOULDBLOCK)); if (nr_bytes > 0) { - php_stream_notify_progress_increment(stream->context, nr_bytes, 0); + php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0); } if (nr_bytes < 0) { @@ -666,7 +666,7 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ return -1; } - if (stream->context && (tmpzval = php_stream_context_get_option(stream->context, "socket", "bindto")) != NULL) { + if (PHP_STREAM_CONTEXT(stream) && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "bindto")) != NULL) { if (Z_TYPE_P(tmpzval) != IS_STRING) { if (xparam->want_errortext) { spprintf(&xparam->outputs.error_text, 0, "local_addr context option is not a string."); @@ -744,9 +744,9 @@ static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+"); if (xparam->outputs.client) { - xparam->outputs.client->context = stream->context; - if (stream->context) { - GC_REFCOUNT(stream->context->res)++; + xparam->outputs.client->ctx = stream->ctx; + if (stream->ctx) { + GC_REFCOUNT(stream->ctx)++; } } } -- 2.40.0