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

commit 6c051d7769ef19d12f00723dff8b5615c501ddfa
Author: Matt Caswell <matt@openssl.org>
Date:   Fri Jan 27 13:49:32 2023 +0000

    squash! 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 and an idea from Theo
    Buehler.
    
    Thanks to Octavio Galland for reporting this issue.

---
 crypto/asn1/bio_ndef.c |   43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

--- a/crypto/asn1/bio_ndef.c
+++ b/crypto/asn1/bio_ndef.c
@@ -107,57 +107,60 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *
     BIO *asn_bio = NULL;
     const ASN1_AUX *aux = it->funcs;
     ASN1_STREAM_ARG sarg;
+    BIO *pop_bio = NULL;
 
     if (!aux || !aux->asn1_cb) {
         ASN1err(ASN1_F_BIO_NEW_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED);
         return NULL;
     }
+    ndef_aux = OPENSSL_malloc(sizeof(*ndef_aux));
     asn_bio = BIO_new(BIO_f_asn1());
-    if (asn_bio == NULL)
-        return NULL;
+    if (ndef_aux == NULL || asn_bio == NULL)
+        goto err;
+
+    /* ASN1 bio needs to be next to output BIO */
+    out = BIO_push(asn_bio, out);
+    if (out == NULL)
+        goto err;
+    pop_bio = asn_bio;
 
     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 the callback prepend any digest, cipher, etc., that the BIO's
      * ASN1 structure needs.
      */
 
-    sarg.out = asn_bio;
+    sarg.out = out;
     sarg.ndef_bio = NULL;
     sarg.boundary = NULL;
 
     /*
-     * 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;
-    }
+    if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
+        goto err;
 
     ndef_aux->val = val;
     ndef_aux->it = it;
     ndef_aux->ndef_bio = sarg.ndef_bio;
     ndef_aux->boundary = sarg.boundary;
-    ndef_aux->out = asn_bio;
+    ndef_aux->out = out;
     ndef_aux->derbuf = NULL;
 
-    BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
+    if (BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux) <= 0)
+        goto err;
 
     return sarg.ndef_bio;
+
+ err:
+    /* BIO_pop() is NULL safe */
+    (void)BIO_pop(pop_bio);
+    BIO_free(asn_bio);
+    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