diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 9eeff1455f8f9..ef213a5399378 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -413,10 +413,15 @@ jobs: with: enableOpcache: true jitType: tracing + - name: Generate coverage report + if: ${{ !cancelled() }} + run: make gcovr-xml - uses: codecov/codecov-action@v5 if: ${{ !cancelled() }} with: + disable_search: true fail_ci_if_error: true + files: gcovr.xml token: ${{ secrets.CODECOV_TOKEN }} verbose: true COMMUNITY: diff --git a/Zend/zend_API.c b/Zend/zend_API.c index bd3f89a245025..7363a4a120395 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -4031,7 +4031,7 @@ static zend_always_inline bool zend_is_callable_check_func(const zval *callable, } /* }}} */ -ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, const zend_object *object) /* {{{ */ +ZEND_API zend_string *zend_get_callable_name_ex(const zval *callable, const zend_object *object) /* {{{ */ { try_again: switch (Z_TYPE_P(callable)) { @@ -4089,7 +4089,7 @@ ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, const zend_objec } /* }}} */ -ZEND_API zend_string *zend_get_callable_name(zval *callable) /* {{{ */ +ZEND_API zend_string *zend_get_callable_name(const zval *callable) /* {{{ */ { return zend_get_callable_name_ex(callable, NULL); } @@ -4206,7 +4206,7 @@ ZEND_API bool zend_is_callable_at_frame( } /* }}} */ -ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */ +ZEND_API bool zend_is_callable_ex(const zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */ { /* Determine callability at the first parent user frame. */ const zend_execute_data *frame = EG(current_execute_data); @@ -4221,13 +4221,13 @@ ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t return ret; } -ZEND_API bool zend_is_callable(zval *callable, uint32_t check_flags, zend_string **callable_name) /* {{{ */ +ZEND_API bool zend_is_callable(const zval *callable, uint32_t check_flags, zend_string **callable_name) /* {{{ */ { return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL); } /* }}} */ -ZEND_API zend_result zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */ +ZEND_API zend_result zend_fcall_info_init(const zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */ { if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, fcc, error)) { return FAILURE; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 60acbd63044d7..e56ded4e8f1b5 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -410,13 +410,13 @@ ZEND_API ZEND_COLD void zend_wrong_property_read(const zval *object, zval *prope #define IS_CALLABLE_SUPPRESS_DEPRECATIONS (1<<1) ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc); -ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, const zend_object *object); -ZEND_API zend_string *zend_get_callable_name(zval *callable); +ZEND_API zend_string *zend_get_callable_name_ex(const zval *callable, const zend_object *object); +ZEND_API zend_string *zend_get_callable_name(const zval *callable); ZEND_API bool zend_is_callable_at_frame( const zval *callable, zend_object *object, const zend_execute_data *frame, uint32_t check_flags, zend_fcall_info_cache *fcc, char **error); -ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error); -ZEND_API bool zend_is_callable(zval *callable, uint32_t check_flags, zend_string **callable_name); +ZEND_API bool zend_is_callable_ex(const zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error); +ZEND_API bool zend_is_callable(const zval *callable, uint32_t check_flags, zend_string **callable_name); ZEND_API const char *zend_get_module_version(const char *module_name); ZEND_API zend_result zend_get_module_started(const char *module_name); @@ -701,7 +701,7 @@ ZEND_API zend_result _call_user_function_impl(zval *object, zval *function_name, * fci->params = NULL; * The callable_name argument may be NULL. */ -ZEND_API zend_result zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error); +ZEND_API zend_result zend_fcall_info_init(const zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error); /** Clear arguments connected with zend_fcall_info *fci * If free_mem is not zero then the params array gets free'd as well @@ -2482,7 +2482,7 @@ static zend_always_inline bool zend_parse_arg_resource(zval *arg, zval **dest, b return 1; } -static zend_always_inline bool zend_parse_arg_func(zval *arg, zend_fcall_info *dest_fci, zend_fcall_info_cache *dest_fcc, bool check_null, char **error, bool free_trampoline) +static zend_always_inline bool zend_parse_arg_func(const zval *arg, zend_fcall_info *dest_fci, zend_fcall_info_cache *dest_fcc, bool check_null, char **error, bool free_trampoline) { if (check_null && UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) { dest_fci->size = 0; diff --git a/build/Makefile.gcov b/build/Makefile.gcov index de85893398cd5..d389cecdd1926 100644 --- a/build/Makefile.gcov +++ b/build/Makefile.gcov @@ -22,8 +22,12 @@ GCOVR_EXCLUDES = \ 'ext/fileinfo/libmagic/.*' \ 'ext/gd/libgd/.*' \ 'ext/hash/sha3/.*' \ + 'ext/lexbor/lexbor/.*' \ 'ext/mbstring/libmbfl/.*' \ - 'ext/pcre/pcre2lib/.*' + 'ext/pcre/pcre2lib/.*' \ + 'ext/uri/uriparser/.*' + +GCOVR_EXCLUDE_LINES_BY_PATTERN = '.*\b(ZEND_PARSE_PARAMETERS_(START|END|NONE)|Z_PARAM_).*' lcov: lcov-html @@ -49,14 +53,14 @@ gcovr-html: @rm -rf gcovr_html/ @mkdir gcovr_html gcovr -sr . -o gcovr_html/index.html --html --html-details \ - --exclude-directories 'ext/date/lib$$' \ + --exclude-lines-by-pattern $(GCOVR_EXCLUDE_LINES_BY_PATTERN) \ $(foreach lib, $(GCOVR_EXCLUDES), -e $(lib)) gcovr-xml: @echo "Generating gcovr XML" @rm -f gcovr.xml gcovr -sr . -o gcovr.xml --xml \ - --exclude-directories 'ext/date/lib$$' \ + --exclude-lines-by-pattern $(GCOVR_EXCLUDE_LINES_BY_PATTERN) \ $(foreach lib, $(GCOVR_EXCLUDES), -e $(lib)) .PHONY: gcovr-html lcov-html php_lcov.info diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index 4c7648e738cda..0000000000000 --- a/codecov.yml +++ /dev/null @@ -1,15 +0,0 @@ -ignore: - # bundled libraries - - "ext/lexbor/lexbor/core" - - "ext/lexbor/lexbor/css" - - "ext/lexbor/lexbor/dom" - - "ext/lexbor/lexbor/encoding" - - "ext/lexbor/lexbor/html" - - "ext/lexbor/lexbor/ns" - - "ext/lexbor/lexbor/ports" - - "ext/lexbor/lexbor/punycode" - - "ext/lexbor/lexbor/tag" - - "ext/lexbor/lexbor/unicode" - - "ext/lexbor/lexbor/url" - - "ext/pcre/pcre2lib" - - "ext/uri/uriparser" diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 95b624ef1d2d2..c5987f3c9e7a4 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -1216,17 +1216,17 @@ PHP_FUNCTION(mb_language) ZEND_PARSE_PARAMETERS_END(); if (name == NULL) { - RETVAL_STRING((char *)mbfl_no_language2name(MBSTRG(language))); + RETVAL_STRING(mbfl_no_language2name(MBSTRG(language))); } else { - zend_string *ini_name = ZSTR_INIT_LITERAL("mbstring.language", 0); + zend_string *ini_name = ZSTR_INIT_LITERAL("mbstring.language", false); if (FAILURE == zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME)) { zend_argument_value_error(1, "must be a valid language, \"%s\" given", ZSTR_VAL(name)); - zend_string_release_ex(ini_name, 0); + zend_string_release_ex(ini_name, false); RETURN_THROWS(); } // TODO Make return void RETVAL_TRUE; - zend_string_release_ex(ini_name, 0); + zend_string_release_ex(ini_name, false); } } /* }}} */ @@ -1509,7 +1509,7 @@ PHP_FUNCTION(mb_preferred_mime_name) php_error_docref(NULL, E_WARNING, "No MIME preferred name corresponding to \"%s\"", name); RETVAL_FALSE; } else { - RETVAL_STRING((char *)preferred_name); + RETVAL_STRING(preferred_name); } } /* }}} */ @@ -3517,7 +3517,7 @@ PHP_FUNCTION(mb_detect_encoding) RETURN_FALSE; } - RETVAL_STRING((char *)ret->name); + RETVAL_STRING(ret->name); } /* }}} */ @@ -3563,7 +3563,7 @@ PHP_FUNCTION(mb_encoding_aliases) array_init(return_value); if (encoding->aliases != NULL) { for (const char **alias = encoding->aliases; *alias; ++alias) { - add_next_index_string(return_value, (char *)*alias); + add_next_index_string(return_value, *alias); } } } @@ -4768,7 +4768,7 @@ PHP_FUNCTION(mb_send_mail) str_headers = smart_str_extract(&str); - zend_string *force_extra_parameters = zend_ini_str_ex("mail.force_extra_parameters", strlen("mail.force_extra_parameters"), false, NULL); + zend_string *force_extra_parameters = zend_ini_str_literal("mail.force_extra_parameters"); if (force_extra_parameters) { extra_cmd = php_escape_shell_cmd(force_extra_parameters); } else if (extra_cmd) { @@ -4804,7 +4804,7 @@ PHP_FUNCTION(mb_get_info) { zend_string *type = NULL; size_t n; - char *name; + const char *name; zval row; const mbfl_encoding **entry; const mbfl_language *lang = mbfl_no2language(MBSTRG(language)); @@ -4819,26 +4819,26 @@ PHP_FUNCTION(mb_get_info) if (!type || zend_string_equals_literal_ci(type, "all")) { array_init(return_value); if (MBSTRG(current_internal_encoding)) { - add_assoc_string(return_value, "internal_encoding", (char *)MBSTRG(current_internal_encoding)->name); + add_assoc_string(return_value, "internal_encoding", MBSTRG(current_internal_encoding)->name); } if (MBSTRG(http_input_identify)) { - add_assoc_string(return_value, "http_input", (char *)MBSTRG(http_input_identify)->name); + add_assoc_string(return_value, "http_input", MBSTRG(http_input_identify)->name); } if (MBSTRG(current_http_output_encoding)) { - add_assoc_string(return_value, "http_output", (char *)MBSTRG(current_http_output_encoding)->name); + add_assoc_string(return_value, "http_output", MBSTRG(current_http_output_encoding)->name); } add_assoc_str(return_value, "http_output_conv_mimetypes", - zend_ini_str("mbstring.http_output_conv_mimetypes", sizeof("mbstring.http_output_conv_mimetypes") - 1, 0) + zend_string_copy(zend_ini_str_literal("mbstring.http_output_conv_mimetypes")) ); - name = (char *)mbfl_no_encoding2name(lang->mail_charset); + name = mbfl_no_encoding2name(lang->mail_charset); add_assoc_string(return_value, "mail_charset", name); - name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding); + name = mbfl_no_encoding2name(lang->mail_header_encoding); add_assoc_string(return_value, "mail_header_encoding", name); - name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding); + name = mbfl_no_encoding2name(lang->mail_body_encoding); add_assoc_string(return_value, "mail_body_encoding", name); add_assoc_long(return_value, "illegal_chars", MBSTRG(illegalchars)); @@ -4849,7 +4849,7 @@ PHP_FUNCTION(mb_get_info) add_assoc_string(return_value, "encoding_translation", "Off"); } - name = (char *)mbfl_no_language2name(MBSTRG(language)); + name = mbfl_no_language2name(MBSTRG(language)); add_assoc_string(return_value, "language", name); // TODO Seems to always have one entry at least? @@ -4880,31 +4880,25 @@ PHP_FUNCTION(mb_get_info) } } else if (zend_string_equals_literal_ci(type, "internal_encoding")) { ZEND_ASSERT(MBSTRG(current_internal_encoding)); - RETURN_STRING((char *)MBSTRG(current_internal_encoding)->name); + RETURN_STRING(MBSTRG(current_internal_encoding)->name); } else if (zend_string_equals_literal_ci(type, "http_input")) { if (MBSTRG(http_input_identify)) { - RETURN_STRING((char *)MBSTRG(http_input_identify)->name); + RETURN_STRING(MBSTRG(http_input_identify)->name); } RETURN_NULL(); } else if (zend_string_equals_literal_ci(type, "http_output")) { ZEND_ASSERT(MBSTRG(current_http_output_encoding)); - RETURN_STRING((char *)MBSTRG(current_http_output_encoding)->name); + RETURN_STRING(MBSTRG(current_http_output_encoding)->name); } else if (zend_string_equals_literal_ci(type, "http_output_conv_mimetypes")) { - RETURN_STR( - zend_ini_str( - "mbstring.http_output_conv_mimetypes", - sizeof("mbstring.http_output_conv_mimetypes") - 1, - false - ) - ); + RETURN_STR_COPY(zend_ini_str_literal("mbstring.http_output_conv_mimetypes")); } else if (zend_string_equals_literal_ci(type, "mail_charset")) { - name = (char *)mbfl_no_encoding2name(lang->mail_charset); + name = mbfl_no_encoding2name(lang->mail_charset); RETURN_STRING(name); } else if (zend_string_equals_literal_ci(type, "mail_header_encoding")) { - name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding); + name = mbfl_no_encoding2name(lang->mail_header_encoding); RETURN_STRING(name); } else if (zend_string_equals_literal_ci(type, "mail_body_encoding")) { - name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding); + name = mbfl_no_encoding2name(lang->mail_body_encoding); RETURN_STRING(name); } else if (zend_string_equals_literal_ci(type, "illegal_chars")) { RETURN_LONG(MBSTRG(illegalchars)); @@ -4915,7 +4909,7 @@ PHP_FUNCTION(mb_get_info) RETURN_STRING("Off"); } } else if (zend_string_equals_literal_ci(type, "language")) { - name = (char *)mbfl_no_language2name(MBSTRG(language)); + name = mbfl_no_language2name(MBSTRG(language)); RETURN_STRING(name); } else if (zend_string_equals_literal_ci(type, "detect_order")) { // TODO Seems to always have one entry at least? diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 4baa199888914..884a1a0b85734 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1102,7 +1102,7 @@ PHP_FUNCTION(openssl_x509_parse) for (i = 0; i < X509_PURPOSE_get_count(); i++) { int id, purpset; char * pname; - X509_PURPOSE * purp; + const X509_PURPOSE * purp; zval subsub; array_init(&subsub); @@ -1177,6 +1177,7 @@ PHP_FUNCTION(openssl_x509_parse) err_subitem: zval_ptr_dtor(&subitem); + zval_ptr_dtor(&critext); err: zend_array_destroy(Z_ARR_P(return_value)); if (cert_str) { @@ -1452,7 +1453,7 @@ PHP_FUNCTION(openssl_pkcs12_export) if (p12 != NULL) { bio_out = BIO_new(BIO_s_mem()); - if (i2d_PKCS12_bio(bio_out, p12)) { + if (bio_out && i2d_PKCS12_bio(bio_out, p12)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); @@ -1530,6 +1531,10 @@ PHP_FUNCTION(openssl_pkcs12_read) if (pkey) { bio_out = BIO_new(BIO_s_mem()); + if (!bio_out) { + goto cleanup; + } + if (PEM_write_bio_PrivateKey(bio_out, pkey, NULL, NULL, 0, 0, NULL)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); @@ -1544,13 +1549,16 @@ PHP_FUNCTION(openssl_pkcs12_read) cert_num = sk_X509_num(ca); if (ca && cert_num) { array_init(&zextracerts); + bio_out = BIO_new(BIO_s_mem()); + if (!bio_out) { + goto cleanup; + } for (i = 0; i < cert_num; i++) { zval zextracert; X509* aCA = sk_X509_pop(ca); if (!aCA) break; - bio_out = BIO_new(BIO_s_mem()); if (PEM_write_bio_X509(bio_out, aCA)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); @@ -1558,9 +1566,10 @@ PHP_FUNCTION(openssl_pkcs12_read) add_index_zval(&zextracerts, i, &zextracert); } + BIO_reset(bio_out); X509_free(aCA); - BIO_free(bio_out); } + BIO_free(bio_out); sk_X509_free(ca); add_assoc_zval(zout, "extracerts", &zextracerts); @@ -2459,12 +2468,14 @@ PHP_FUNCTION(openssl_pbkdf2) if (PKCS5_PBKDF2_HMAC(password, (int)password_len, (unsigned char *)salt, (int)salt_len, (int)iterations, digest, (int)key_length, (unsigned char*)ZSTR_VAL(out_buffer)) == 1) { ZSTR_VAL(out_buffer)[key_length] = 0; - RETURN_NEW_STR(out_buffer); + RETVAL_NEW_STR(out_buffer); } else { php_openssl_store_errors(); zend_string_release_ex(out_buffer, 0); - RETURN_FALSE; + RETVAL_FALSE; } + + php_openssl_release_evp_md(digest); } /* }}} */ @@ -2811,33 +2822,41 @@ PHP_FUNCTION(openssl_pkcs7_read) } if (certs != NULL) { + bio_out = BIO_new(BIO_s_mem()); + if (!bio_out) { + goto clean_exit; + } for (i = 0; i < sk_X509_num(certs); i++) { X509* ca = sk_X509_value(certs, i); - bio_out = BIO_new(BIO_s_mem()); - if (bio_out && PEM_write_bio_X509(bio_out, ca)) { + if (PEM_write_bio_X509(bio_out, ca)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); } - BIO_free(bio_out); + BIO_reset(bio_out); } + BIO_free(bio_out); } if (crls != NULL) { + bio_out = BIO_new(BIO_s_mem()); + if (!bio_out) { + goto clean_exit; + } for (i = 0; i < sk_X509_CRL_num(crls); i++) { X509_CRL* crl = sk_X509_CRL_value(crls, i); - bio_out = BIO_new(BIO_s_mem()); - if (bio_out && PEM_write_bio_X509_CRL(bio_out, crl)) { + if (PEM_write_bio_X509_CRL(bio_out, crl)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); } - BIO_free(bio_out); + BIO_reset(bio_out); } + BIO_free(bio_out); } RETVAL_TRUE; @@ -3478,33 +3497,43 @@ PHP_FUNCTION(openssl_cms_read) } if (certs != NULL) { + bio_out = BIO_new(BIO_s_mem()); + if (!bio_out) { + goto clean_exit; + } + for (i = 0; i < sk_X509_num(certs); i++) { X509* ca = sk_X509_value(certs, i); - bio_out = BIO_new(BIO_s_mem()); - if (bio_out && PEM_write_bio_X509(bio_out, ca)) { + if (PEM_write_bio_X509(bio_out, ca)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); } - BIO_free(bio_out); + BIO_reset(bio_out); } + BIO_free(bio_out); } if (crls != NULL) { + bio_out = BIO_new(BIO_s_mem()); + if (!bio_out) { + goto clean_exit; + } + for (i = 0; i < sk_X509_CRL_num(crls); i++) { X509_CRL* crl = sk_X509_CRL_value(crls, i); - bio_out = BIO_new(BIO_s_mem()); - if (bio_out && PEM_write_bio_X509_CRL(bio_out, crl)) { + if (PEM_write_bio_X509_CRL(bio_out, crl)) { BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length); add_index_zval(zout, i, &zcert); } - BIO_free(bio_out); + BIO_reset(bio_out); } + BIO_free(bio_out); } RETVAL_TRUE; diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c index 533d2f2c61f1b..ed57d6e81715e 100644 --- a/ext/openssl/openssl_backend_common.c +++ b/ext/openssl/openssl_backend_common.c @@ -746,6 +746,7 @@ int php_openssl_check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedch return 0; } if (!X509_STORE_CTX_init(csc, ctx, x, untrustedchain)) { + X509_STORE_CTX_free(csc); php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "Certificate store initialization failed"); return 0; diff --git a/ext/openssl/openssl_backend_v3.c b/ext/openssl/openssl_backend_v3.c index 6e3e883080f3f..a9733b9bdd98c 100644 --- a/ext/openssl/openssl_backend_v3.c +++ b/ext/openssl/openssl_backend_v3.c @@ -454,6 +454,9 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) { } EVP_PKEY_CTX_free(ctx); ctx = EVP_PKEY_CTX_new(param_key, NULL); + if (!ctx) { + goto cleanup; + } } if (EVP_PKEY_check(ctx) || EVP_PKEY_public_check_quick(ctx)) { diff --git a/ext/openssl/openssl_pwhash.c b/ext/openssl/openssl_pwhash.c index dc125e3b516db..69e9dae3fa990 100644 --- a/ext/openssl/openssl_pwhash.c +++ b/ext/openssl/openssl_pwhash.c @@ -51,6 +51,7 @@ ZEND_EXTERN_MODULE_GLOBALS(openssl) static inline zend_result get_options(zend_array *options, uint32_t *memlimit, uint32_t *iterlimit, uint32_t *threads) { zval *opt; + zend_long sthreads; *iterlimit = PHP_OPENSSL_PWHASH_ITERLIMIT; *memlimit = PHP_OPENSSL_PWHASH_MEMLIMIT; @@ -76,8 +77,7 @@ static inline zend_result get_options(zend_array *options, uint32_t *memlimit, u } *iterlimit = siterlimit; } - if ((opt = zend_hash_str_find(options, "threads", strlen("threads"))) && (zval_get_long(opt) != 1)) { - zend_long sthreads = zval_get_long(opt); + if ((opt = zend_hash_str_find(options, "threads", strlen("threads"))) && ((sthreads = zval_get_long(opt)) != 1)) { if ((sthreads < PHP_OPENSSL_THREADS_MIN) || (sthreads > PHP_OPENSSL_THREADS_MAX)) { zend_value_error("Invalid number of threads"); return FAILURE; diff --git a/ext/openssl/tests/gh21031.phpt b/ext/openssl/tests/gh21031.phpt new file mode 100644 index 0000000000000..a35fab9272700 --- /dev/null +++ b/ext/openssl/tests/gh21031.phpt @@ -0,0 +1,82 @@ +--TEST-- +GH-21031 (Fix NULL deref when enabling TLS fails and the peer name needs to be reset) +--EXTENSIONS-- +openssl +--SKIPIF-- + +--FILE-- + [ + 'SNI_server_certs' => [ + "cs.php.net" => __DIR__ . "/sni_server_cs_expired.pem", + ] + ]]); + + $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr, $serverFlags, $ctx); + phpt_notify_server_start($server); + + $conn = stream_socket_accept($server, 3); + fclose($conn); + + phpt_wait(); +CODE; + +$proxyCode = <<<'CODE' + $flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN; + $server = stream_socket_server("tcp://127.0.0.1:0", $errornum, $errorstr, $flags); + phpt_notify_server_start($server); + + $upstream = stream_socket_client("tcp://{{ ADDR }}", $errornum, $errorstr, 30, STREAM_CLIENT_CONNECT); + stream_set_blocking($upstream, false); + + $conn = stream_socket_accept($server); + stream_set_blocking($conn, true); + + // reading CONNECT request headers + while (($line = fgets($conn)) !== false) { + if (rtrim($line) === '') break; // empty line means end of headers + } + + // successful CONNECT response + fwrite($conn, "HTTP/1.0 200 Connection established\r\n\r\n"); + + fclose($conn); + fclose($upstream); + phpt_wait(); +CODE; + +$clientCode = <<<'CODE' + $clientCtx = stream_context_create([ + 'ssl' => [ + 'cafile' => __DIR__ . '/sni_server_ca.pem', + 'verify_peer' => true, + 'verify_peer_name' => true, + ], + "http" => [ + "proxy" => "tcp://{{ ADDR }}" + ], + ]); + + var_dump(file_get_contents("https://cs.php.net/", false, $clientCtx)); + + phpt_notify('proxy'); + phpt_notify('server'); +CODE; + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, [ + 'server' => $serverCode, + 'proxy' => $proxyCode, +]); +?> +--EXPECTF-- +Warning: file_get_contents(https://cs.php.net/): Failed to open stream: Cannot connect to HTTPS server through proxy in %s +bool(false) diff --git a/ext/openssl/tests/openssl_pbkdf2_basic.phpt b/ext/openssl/tests/openssl_pbkdf2_basic.phpt index fd253ac78bb2f..ba79f9415ba82 100644 --- a/ext/openssl/tests/openssl_pbkdf2_basic.phpt +++ b/ext/openssl/tests/openssl_pbkdf2_basic.phpt @@ -19,6 +19,8 @@ var_dump(bin2hex(openssl_pbkdf2('password', 'salt', 20, 16777216))); var_dump(bin2hex(openssl_pbkdf2('passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 25, 4096))); var_dump(bin2hex(openssl_pbkdf2("pass\0word", "sa\0lt", 16, 4096))); +var_dump(bin2hex(openssl_pbkdf2("password", "salt", 16, 4096, "sha-256"))); + ?> --EXPECT-- string(40) "0c60c80f961f0e71f3a9b524af6012062fe037a6" @@ -26,3 +28,4 @@ string(40) "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957" string(40) "4b007901b765489abead49d926f721d065a429c1" string(50) "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038" string(32) "56fa6aa75548099dcc37d7f03425e0c3" +string(32) "c5e478d59288c841aa530db6845c4c8d" diff --git a/ext/openssl/tests/sni_server_cs_expired.pem b/ext/openssl/tests/sni_server_cs_expired.pem new file mode 100644 index 0000000000000..9f5a201b26d1b --- /dev/null +++ b/ext/openssl/tests/sni_server_cs_expired.pem @@ -0,0 +1,57 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAvy5NhzktzEdsHTbGB6vqYANms5rn1zXFmTJrGlWCwoIsNmTf +ahvZkrC1cCXTZ7fbPB8XQbpAtz2ZSU7OcwBW9B8okYUPo9zi/ptwcrgsQsN0hrcD +8MBRUccevwime5fLvg8E9RJ/68y9y3BnRcVWYO2sAK9juTfidNjETU3Bb05oXv8D +SD/6onXQu4uXDgsQ3cRXeld9UB0xazmQXyyiIqXc/cpTAnaEVYzn28aj7NlUbzNq +511UXMXY44x9EcXWpPVZ7heNcJNzY5DCNzmtXKrt9yiMpWQcPXEzsESVxAMqib9u +TFOlvVX17LIPxBG656PjTD9J1h6kBbMCUxzs7wIDAQABAoIBAQC85lBeY0X4ST3v +I7bJz7kWQ2YP4uhfAdeLhoDDFWjNLffniwYhfwEc6xNri0R2f/jUT9gX7qORKwEx +qPdeNCC2t67LElGg1FlJv2Z9Q7MgCKYzkdQH5s6y4e9kTHTLO/JpiceZKz1QTQ3f +XOH9032E6nIAf0wmr6xHTgOwajrN8VI5BuPEMVmEwIw3AtYeqVuPCNKyGR4HUVkC +2bAydnGngbRJRnNzmKcWJancxpHDGBSFqPyuXMFC7Jgo3ZmyCbGp99vuXVk/sW9x +5aj94M9nRE0guk05ivH2/JZao2uLYkIgjFWlhNxKdWgWRk8DEuN4djC8mKS9YH1q +crYRToMhAoGBAOspUTtKP54mpZmyhxuDqj02JaJRzNTskPHsiF1UhtXuw7uT+ryV +ekUFLNXoFmn9mbx1WVaUvGH4qjilvQOxz7u++lz0ApqJEfyM3jc/cC40Y5zcuGSu +Etbg+SyDoytlgMCIydJyrS7NNALSo5p5oG6XY2f8yd/DCAmo8LzypaHRAoGBANAf +R1SlBMc/bOsi6GrJxcBVSCFMiKYiO5woL5aUKa9yM+UQuQ/6xbQ7Q+sOlt0FH3xo +AJ2L60qTdjyXVtjOdtXs5ZC4l+C6AfnCx6yLr+fNc4SOYXEfqS4LZylgwKd9KyVB +asspIW9Idbgebmi6vPyt9LDkIp0h1VuFGjkvQJK/AoGBAI4pbS0dprXyARyYW6sb +fpgAmuG099IkrT9DUfCx/81myTclr2fAKal+BmvOIXaz0/OlMXvw8K19iVIzh7+r +B70lJ+93p/dKM/BsLI5TsHqOO0YB/QsIXOVAHgJ2FfdPJnW+e9vYba+kZ/Po6PSi +4ITaykJ8BIJcQgis89QWEGFxAoGBAJhQO+jzuDKF9ZWEf6ofrw0anOZZ16wWY5/e +PS2rk3JmVxpuibHrKqPDt+ogTELHDAsFJmYmz3VNxHuFmrajK49Wh4/JuMVr/CQo +6+8YcA1qa/94IFIlBLDBAafjujsZvOjQHnM+z8xcsGKmStF00Pjv6qNG4xoyd646 +FD4DmfOLAoGAWXehpopZKXE9gRAni881ucK6WqxPPBoofbozi09D0MmfarIVaSkv +jNVVHBfLWd7IEXTjiipPBeUqq6Jc3pscN1Vp4rrl8jTmVTdazEv0LuzpdUFqmNo2 +M+xw17uz9D9Q32/aW1Lar0PdIaL/wGEDEyzEBFwrGppcENLilPz8gzU= +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIFIjCCAwqgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UEBhMCR0Ix +EDAOBgNVBAgMB0VuZ2xhbmQxEDAOBgNVBAoMB1BIUC5uZXQxEDAOBgNVBAsMB29w +ZW5zc2wxEDAOBgNVBAMMB3BocC5uZXQwHhcNMTgwMTE0MTgzNjEyWhcNMjYwNDAy +MTgzNjEyWjBGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UE +CgwHUEhQLm5ldDETMBEGA1UEAwwKY3MucGhwLm5ldDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAL8uTYc5LcxHbB02xger6mADZrOa59c1xZkyaxpVgsKC +LDZk32ob2ZKwtXAl02e32zwfF0G6QLc9mUlOznMAVvQfKJGFD6Pc4v6bcHK4LELD +dIa3A/DAUVHHHr8IpnuXy74PBPUSf+vMvctwZ0XFVmDtrACvY7k34nTYxE1NwW9O +aF7/A0g/+qJ10LuLlw4LEN3EV3pXfVAdMWs5kF8soiKl3P3KUwJ2hFWM59vGo+zZ +VG8zauddVFzF2OOMfRHF1qT1We4XjXCTc2OQwjc5rVyq7fcojKVkHD1xM7BElcQD +Kom/bkxTpb1V9eyyD8QRuuej40w/SdYepAWzAlMc7O8CAwEAAaOCAQkwggEFMAkG +A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMGCWCGSAGG+EIBDQQmFiRPcGVu +U1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFHPfd8dK +Lz1R0Ck4WV1B9AWXd5DSMGwGA1UdIwRlMGOAFOPK44Eacedv7HbR2Igcbew+4kUa +oUekRTBDMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEQMA4GA1UECgwH +UEhQLm5ldDEQMA4GA1UEAwwHcGhwLm5ldIICEAAwDgYDVR0PAQH/BAQDAgWgMBMG +A1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQB6WSIHEyDXLZxH +hZjqSNQOA7Wc9Z2FCAiD29xYkGTL8WuPVGGP1mu4B92ytj+PMWwqSReDa7eTGLE7 +O7ozw9l+c+gNmHFNikSsGjlV2E8CToQOFMny+jAQYMSXf8UbTp9xDfgG02t/71hv +SLWqdeHMLcR0xi0nBQH0vDOkwUbuWYqFa3jejHieGhykHM6CkIk6lqnyOEO+ooIF +ZsLprrg1ss/mXCPI6niP0hze55ERKdxI7Rk8sZ4pVkf2SUWqZrUS0aJ+Ymmwi6Xd +2V7izq5N30PkJS8MtqII4FAjRBIkwPh0sy8PmW/DzkYU+lYQnDfYLKDFKcj8xJK/ +o8oZUBsQltrSj0KlM9QuqxCTCBCy1nXZ9WHOhq+jdLiTc1Oi60uEHcUMrLK8aYc4 +HqIvZS6C2iwMI0d1OP3VxmAbMQ9yqRi+FbLYavJ3H40jrU9SYqdxa0BrTaz8MJNE +6AEwgQDPChczSghvHME+Fs4mtGCY3TesbNZKVahQRjaFIhMZIZ4RP4CRc0bJOBG+ +8Me4+KHNsD2ki5b03wAN6C1P2QrMzI+gH9fXLZYp761ciDAsX6YIzrhHHYLxYpJH +BkQKKs8dCQWE5IzgVrdlvC3Z1/l9om66wHqqx7nKnPfYs/Sfnwe9MpCD6xJrXiTm +WS7NM6fbQpO9APNr7o0ZOjbbWFzlNw== +-----END CERTIFICATE----- diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 8f9395e460223..5928994d12af0 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -1508,7 +1508,7 @@ static unsigned char *php_openssl_alpn_protos_parse(unsigned short *outlen, cons return NULL; } - out = emalloc(strlen(in) + 1); + out = emalloc(len + 1); for (i = 0; i <= len; ++i) { if (i == len || in[i] == ',') { diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 1891347e2a66b..6d9f7331afb31 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -546,6 +546,10 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1); if (php_stream_write(stream, ZSTR_VAL(header.s), ZSTR_LEN(header.s)) != ZSTR_LEN(header.s)) { + if (reset_ssl_peer_name) { + php_stream_context_unset_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_name"); + } + php_stream_wrapper_log_error(wrapper, options, "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; @@ -567,16 +571,18 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, /* enable SSL transport layer */ if (stream) { + php_stream_context *old_context = PHP_STREAM_CONTEXT(stream); + if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(stream, 1) < 0) { php_stream_wrapper_log_error(wrapper, options, "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; } - } - if (reset_ssl_peer_name) { - php_stream_context_unset_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_name"); + if (reset_ssl_peer_name) { + php_stream_context_unset_option(old_context, "ssl", "peer_name"); + } } }