[php-src] master: openssl: Fix checks on BIO_get_mem_ptr() (#20998)
Nora Dossche via GitHub <[email protected]> Mon, 3 Aug 2026 18:41:33 +0000
| Newsgroups | gmane.comp.php.cvs.general |
|---|---|
| Message-ID | <[email protected]> |
Author: Nora Dossche (ndossche)
Committer: GitHub (web-flow)
Pusher: ndossche
Date: 2026-08-03T20:41:29+02:00
Commit: https://github.com/php/php-src/commit/9d7480ee2ec3f6c17e658069fac178f7719b6cfb
Raw diff: https://github.com/php/php-src/commit/9d7480ee2ec3f6c17e658069fac178f7719b6cfb.diff
openssl: Fix checks on BIO_get_mem_ptr() (#20998)
If the call fails, then the pointer remains uninitialized, and this
triggers undefined behaviour or the reading of a dangling pointer.
In my own tests this came out as a UAF. However, it seems not
exploitable by an attacker as failure should be not controllable.
It's worth pointing out that OpenSSL checks the return value in its own
code that calls this function as well [1].
[1] https://github.com/openssl/openssl/blob/b2ecef451ccede07366023da4553f113f6e4fe71/apps/lib/apps.c#L3307-L3311
Changed paths:
M ext/openssl/openssl.c
Diff:
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 55a437c0865a..80c0a8bab073 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -1129,6 +1129,7 @@ PHP_FUNCTION(openssl_spki_export)
EVP_PKEY *pkey = NULL;
NETSCAPE_SPKI *spki = NULL;
BIO *out = NULL;
+ BUF_MEM *bio_buf;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
RETURN_THROWS();
@@ -1158,10 +1159,7 @@ PHP_FUNCTION(openssl_spki_export)
}
out = BIO_new(BIO_s_mem());
- if (out && PEM_write_bio_PUBKEY(out, pkey)) {
- BUF_MEM *bio_buf;
-
- BIO_get_mem_ptr(out, &bio_buf);
+ if (out && PEM_write_bio_PUBKEY(out, pkey) && BIO_get_mem_ptr(out, &bio_buf) > 0) {
RETVAL_STRINGL((char *)bio_buf->data, bio_buf->length);
} else {
php_openssl_store_errors();
@@ -1232,6 +1230,7 @@ PHP_FUNCTION(openssl_x509_export)
zval *zout;
bool notext = 1;
BIO * bio_out;
+ BUF_MEM *bio_buf;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_OBJ_OF_CLASS_OR_STR(cert_obj, php_openssl_certificate_ce, cert_str)
@@ -1255,10 +1254,7 @@ PHP_FUNCTION(openssl_x509_export)
}
if (!notext && !X509_print(bio_out, cert)) {
php_openssl_store_errors();
- } else if (PEM_write_bio_X509(bio_out, cert)) {
- BUF_MEM *bio_buf;
-
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ } else if (PEM_write_bio_X509(bio_out, cert) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZEND_TRY_ASSIGN_REF_STRINGL(zout, bio_buf->data, bio_buf->length);
RETVAL_TRUE;
@@ -1539,8 +1535,7 @@ PHP_FUNCTION(openssl_x509_parse)
goto err_subitem;
}
if (nid == NID_subject_alt_name) {
- if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) {
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ if (openssl_x509v3_subjectAltName(bio_out, extension) == 0 && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length);
} else {
BIO_free(bio_out);
@@ -1548,7 +1543,10 @@ PHP_FUNCTION(openssl_x509_parse)
}
}
else if (X509V3_EXT_print(bio_out, extension, 0, 0) > 0) {
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ if (BIO_get_mem_ptr(bio_out, &bio_buf) <= 0) {
+ BIO_free(bio_out);
+ goto err_subitem;
+ }
add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length);
} else {
php_openssl_add_assoc_asn1_string(&subitem, extname, X509_EXTENSION_get_data(extension));
@@ -1854,11 +1852,9 @@ PHP_FUNCTION(openssl_pkcs12_export)
p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
if (p12 != NULL) {
+ BUF_MEM *bio_buf;
bio_out = BIO_new(BIO_s_mem());
- if (bio_out && i2d_PKCS12_bio(bio_out, p12)) {
- BUF_MEM *bio_buf;
-
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ if (bio_out && i2d_PKCS12_bio(bio_out, p12) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZEND_TRY_ASSIGN_REF_STRINGL(zout, bio_buf->data, bio_buf->length);
RETVAL_TRUE;
@@ -1920,10 +1916,9 @@ PHP_FUNCTION(openssl_pkcs12_read)
}
if (cert) {
+ BUF_MEM *bio_buf;
bio_out = BIO_new(BIO_s_mem());
- if (bio_out && PEM_write_bio_X509(bio_out, cert)) {
- BUF_MEM *bio_buf;
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ if (bio_out && PEM_write_bio_X509(bio_out, cert) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
add_assoc_zval(zout, "cert", &zcert);
} else {
@@ -1933,14 +1928,13 @@ PHP_FUNCTION(openssl_pkcs12_read)
}
if (pkey) {
+ BUF_MEM *bio_buf;
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);
+ if (PEM_write_bio_PrivateKey(bio_out, pkey, NULL, NULL, 0, 0, NULL) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZVAL_STRINGL(&zpkey, bio_buf->data, bio_buf->length);
add_assoc_zval(zout, "pkey", &zpkey);
} else {
@@ -1959,12 +1953,11 @@ PHP_FUNCTION(openssl_pkcs12_read)
for (i = 0; i < cert_num; i++) {
zval zextracert;
+ BUF_MEM *bio_buf;
X509* aCA = sk_X509_pop(ca);
if (!aCA) break;
- if (PEM_write_bio_X509(bio_out, aCA)) {
- BUF_MEM *bio_buf;
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ if (PEM_write_bio_X509(bio_out, aCA) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZVAL_STRINGL(&zextracert, bio_buf->data, bio_buf->length);
add_index_zval(&zextracerts, i, &zextracert);
}
@@ -2061,6 +2054,7 @@ PHP_FUNCTION(openssl_csr_export)
zval *zout;
bool notext = 1;
BIO * bio_out;
+ BUF_MEM *bio_buf;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_OBJ_OF_CLASS_OR_STR(csr_obj, php_openssl_request_ce, csr_str)
@@ -2082,10 +2076,7 @@ PHP_FUNCTION(openssl_csr_export)
bio_out = BIO_new(BIO_s_mem());
if (!notext && !X509_REQ_print(bio_out, csr)) {
php_openssl_store_errors();
- } else if (PEM_write_bio_X509_REQ(bio_out, csr)) {
- BUF_MEM *bio_buf;
-
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ } else if (PEM_write_bio_X509_REQ(bio_out, csr) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZEND_TRY_ASSIGN_REF_STRINGL(zout, bio_buf->data, bio_buf->length);
RETVAL_TRUE;
@@ -3243,11 +3234,10 @@ PHP_FUNCTION(openssl_pkcs7_read)
goto clean_exit;
}
for (i = 0; i < sk_X509_num(certs); i++) {
+ BUF_MEM *bio_buf;
X509* ca = sk_X509_value(certs, i);
- if (PEM_write_bio_X509(bio_out, ca)) {
- BUF_MEM *bio_buf;
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ if (PEM_write_bio_X509(bio_out, ca) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
add_index_zval(zout, i, &zcert);
}
@@ -3262,11 +3252,10 @@ PHP_FUNCTION(openssl_pkcs7_read)
goto clean_exit;
}
for (i = 0; i < sk_X509_CRL_num(crls); i++) {
+ BUF_MEM *bio_buf;
X509_CRL* crl = sk_X509_CRL_value(crls, i);
- if (PEM_write_bio_X509_CRL(bio_out, crl)) {
- BUF_MEM *bio_buf;
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ if (PEM_write_bio_X509_CRL(bio_out, crl) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
add_index_zval(zout, i, &zcert);
}
@@ -3919,11 +3908,10 @@ PHP_FUNCTION(openssl_cms_read)
}
for (i = 0; i < sk_X509_num(certs); i++) {
+ BUF_MEM *bio_buf;
X509* ca = sk_X509_value(certs, i);
- if (PEM_write_bio_X509(bio_out, ca)) {
- BUF_MEM *bio_buf;
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ if (PEM_write_bio_X509(bio_out, ca) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
add_index_zval(zout, i, &zcert);
}
@@ -3939,11 +3927,10 @@ PHP_FUNCTION(openssl_cms_read)
}
for (i = 0; i < sk_X509_CRL_num(crls); i++) {
+ BUF_MEM *bio_buf;
X509_CRL* crl = sk_X509_CRL_value(crls, i);
- if (PEM_write_bio_X509_CRL(bio_out, crl)) {
- BUF_MEM *bio_buf;
- BIO_get_mem_ptr(bio_out, &bio_buf);
+ if (PEM_write_bio_X509_CRL(bio_out, crl) && BIO_get_mem_ptr(bio_out, &bio_buf) > 0) {
ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
add_index_zval(zout, i, &zcert);
}