Commit 16be8273ad for openssl.org
commit 16be8273addbb7c667e9ff12fdb6bf892c43d161
Author: Neil Horman <nhorman@openssl.org>
Date: Fri Jun 26 13:06:20 2026 -0400
Replace use of CRYPTO_GET_REF in bio_lib
BIO_free_all makes use of CRYPTO_GET_REF to determine if there is
another user of a BIO chain at some artibrary point within the chain.
But CRYPTO_GET_REF is begging for a TOCTOU error, and so we're
deprecating it.
replace the use of GET_REF with an internal version of BIO_free that
returns the value of the resultant ref count, and use that instead, so
we are TOCTOU free
Reviewed-by: Kurt Roeckx <kurt@roeckx.be>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Norbert Pocs <norbertp@openssl.org>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Bob Beck <beck@openssl.org>
MergeDate: Sat Jul 4 16:47:13 2026
(Merged from https://github.com/openssl/openssl/pull/31750)
diff --git a/crypto/bio/bio_lib.c b/crypto/bio/bio_lib.c
index b7d4bc549e..dbd55c8b2f 100644
--- a/crypto/bio/bio_lib.c
+++ b/crypto/bio/bio_lib.c
@@ -116,24 +116,22 @@ BIO *BIO_new(const BIO_METHOD *method)
return BIO_new_ex(NULL, method);
}
-int BIO_free(BIO *a)
+static int BIO_free_int(BIO *a, int *ret)
{
- int ret;
if (a == NULL)
return 0;
- if (CRYPTO_DOWN_REF(&a->references, &ret) <= 0)
+ if (CRYPTO_DOWN_REF(&a->references, ret) <= 0)
return 0;
- REF_PRINT_COUNT("BIO", ret, a);
- if (ret > 0)
+ REF_PRINT_COUNT("BIO", *ret, a);
+ if (*ret > 0)
return 1;
- REF_ASSERT_ISNT(ret < 0);
+ REF_ASSERT_ISNT(*ret < 0);
if (HAS_CALLBACK(a)) {
- ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL);
- if (ret <= 0)
+ if ((int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL) <= 0)
return 0;
}
@@ -149,6 +147,13 @@ int BIO_free(BIO *a)
return 1;
}
+int BIO_free(BIO *b)
+{
+ int ref;
+
+ return BIO_free_int(b, &ref);
+}
+
void BIO_set_data(BIO *a, void *ptr)
{
a->ptr = ptr;
@@ -874,11 +879,11 @@ void BIO_free_all(BIO *bio)
while (bio != NULL) {
b = bio;
- CRYPTO_GET_REF(&b->references, &ref);
bio = bio->next_bio;
- BIO_free(b);
- /* Since ref count > 1, don't free anyone else. */
- if (ref > 1)
+ ref = 0;
+ BIO_free_int(b, &ref);
+ /* Since ref count > 0, don't free anyone else. */
+ if (ref > 0)
break;
}
}