File openssl-CVE-2023-0215-1of4.patch of Package openssl-1_0_0.29468

commit 847b1cd5fcf2a9098871f5832a50845670c3885e
Author: Matt Caswell <matt@openssl.org>
Date:   Wed Dec 14 16:18:14 2022 +0000

    Fix a UAF resulting from a bug in BIO_new_NDEF
    
    If the aux->asn1_cb() call fails in BIO_new_NDEF then the "out" BIO will
    be part of an invalid BIO chain. This causes a "use after free" when the
    BIO is eventually freed.
    
    Based on an original patch by Viktor Dukhovni.
    
    Thanks to Octavio Galland for reporting this issue.

---
 crypto/asn1/bio_ndef.c |   52 +++++++++++++++++++++++++++++--------------------
 1 file changed, 31 insertions(+), 21 deletions(-)

--- a/crypto/asn1/bio_ndef.c
+++ b/crypto/asn1/bio_ndef.c
@@ -95,6 +95,12 @@ static int ndef_suffix(BIO *b, unsigned
 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
                             void *parg);
 
+/*
+ * On success, the returned BIO owns the input BIO as part of its BIO chain.
+ * On failure, NULL is returned and the input BIO is owned by the caller.
+ *
+ * Unfortunately cannot constify this due to CMS_stream() and PKCS7_stream()
+ */
 BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
 {
     NDEF_SUPPORT *ndef_aux = NULL;
@@ -106,48 +112,52 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *
         ASN1err(ASN1_F_BIO_NEW_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED);
         return NULL;
     }
-    ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT));
     asn_bio = BIO_new(BIO_f_asn1());
-
-    /* ASN1 bio needs to be next to output BIO */
-
-    out = BIO_push(asn_bio, out);
-
-    if (!ndef_aux || !asn_bio || !out)
-        goto err;
+    if (asn_bio == NULL)
+        return NULL;
 
     BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
     BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
 
+    /* ASN1 bio needs to be next to output BIO */
+    if (BIO_push(asn_bio, out) == NULL) {
+        BIO_free(asn_bio);
+        return NULL;
+    }
+
     /*
-     * Now let callback prepend any digest, cipher etc BIOs ASN1 structure
-     * needs.
+     * Now let the callback prepend any digest, cipher, etc., that the BIO's
+     * ASN1 structure needs.
      */
 
-    sarg.out = out;
+    sarg.out = asn_bio;
     sarg.ndef_bio = NULL;
     sarg.boundary = NULL;
 
-    if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
-        goto err;
+    /*
+     * On error, restore input BIO to head of its BIO chain.
+     *
+     * The asn1_cb(), must not have mutated asn_bio on error, leaving it in the
+     * middle of some partially built, but not returned BIO chain.
+     */
+    if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0
+        || (ndef_aux = OPENSSL_malloc(sizeof(*ndef_aux))) == NULL) {
+        /* Assumed head of BIO chain with "out" as immediate successor */
+        (void)BIO_pop(asn_bio);
+        BIO_free(asn_bio);
+        return NULL;
+    }
 
     ndef_aux->val = val;
     ndef_aux->it = it;
     ndef_aux->ndef_bio = sarg.ndef_bio;
     ndef_aux->boundary = sarg.boundary;
-    ndef_aux->out = out;
+    ndef_aux->out = asn_bio;
     ndef_aux->derbuf = NULL;
 
     BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
 
     return sarg.ndef_bio;
-
- err:
-    if (asn_bio)
-        BIO_free(asn_bio);
-    if (ndef_aux)
-        OPENSSL_free(ndef_aux);
-    return NULL;
 }
 
 static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
openSUSE Build Service is sponsored by