Blame SOURCES/0104-CVE-2023-0215-UAF-bio.patch

3da501
From 8818064ce3c3c0f1b740a5aaba2a987e75bfbafd Mon Sep 17 00:00:00 2001
3da501
From: Matt Caswell <matt@openssl.org>
3da501
Date: Wed, 14 Dec 2022 16:18:14 +0000
3da501
Subject: [PATCH 06/18] Fix a UAF resulting from a bug in BIO_new_NDEF
3da501
3da501
If the aux->asn1_cb() call fails in BIO_new_NDEF then the "out" BIO will
3da501
be part of an invalid BIO chain. This causes a "use after free" when the
3da501
BIO is eventually freed.
3da501
3da501
Based on an original patch by Viktor Dukhovni and an idea from Theo
3da501
Buehler.
3da501
3da501
Thanks to Octavio Galland for reporting this issue.
3da501
3da501
Reviewed-by: Paul Dale <pauli@openssl.org>
3da501
Reviewed-by: Tomas Mraz <tomas@openssl.org>
3da501
---
3da501
 crypto/asn1/bio_ndef.c | 40 ++++++++++++++++++++++++++++++++--------
3da501
 1 file changed, 32 insertions(+), 8 deletions(-)
3da501
3da501
diff --git a/crypto/asn1/bio_ndef.c b/crypto/asn1/bio_ndef.c
3da501
index d94e3a3644..b9df3a7a47 100644
3da501
--- a/crypto/asn1/bio_ndef.c
3da501
+++ b/crypto/asn1/bio_ndef.c
3da501
@@ -49,13 +49,19 @@ static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
3da501
 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
3da501
                             void *parg);
3da501
 
3da501
-/* unfortunately cannot constify this due to CMS_stream() and PKCS7_stream() */
3da501
+/*
3da501
+ * On success, the returned BIO owns the input BIO as part of its BIO chain.
3da501
+ * On failure, NULL is returned and the input BIO is owned by the caller.
3da501
+ *
3da501
+ * Unfortunately cannot constify this due to CMS_stream() and PKCS7_stream()
3da501
+ */
3da501
 BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
3da501
 {
3da501
     NDEF_SUPPORT *ndef_aux = NULL;
3da501
     BIO *asn_bio = NULL;
3da501
     const ASN1_AUX *aux = it->funcs;
3da501
     ASN1_STREAM_ARG sarg;
3da501
+    BIO *pop_bio = NULL;
3da501
 
3da501
     if (!aux || !aux->asn1_cb) {
3da501
         ERR_raise(ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED);
3da501
@@ -70,21 +76,39 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
3da501
     out = BIO_push(asn_bio, out);
3da501
     if (out == NULL)
3da501
         goto err;
3da501
+    pop_bio = asn_bio;
3da501
 
3da501
-    BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
3da501
-    BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
3da501
+    if (BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free) <= 0
3da501
+            || BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free) <= 0
3da501
+            || BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux) <= 0)
3da501
+        goto err;
3da501
 
3da501
     /*
3da501
-     * Now let callback prepends any digest, cipher etc BIOs ASN1 structure
3da501
-     * needs.
3da501
+     * Now let the callback prepend any digest, cipher, etc., that the BIO's
3da501
+     * ASN1 structure needs.
3da501
      */
3da501
 
3da501
     sarg.out = out;
3da501
     sarg.ndef_bio = NULL;
3da501
     sarg.boundary = NULL;
3da501
 
3da501
-    if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
3da501
+    /*
3da501
+     * The asn1_cb(), must not have mutated asn_bio on error, leaving it in the
3da501
+     * middle of some partially built, but not returned BIO chain.
3da501
+     */
3da501
+    if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) {
3da501
+        /*
3da501
+         * ndef_aux is now owned by asn_bio so we must not free it in the err
3da501
+         * clean up block
3da501
+         */
3da501
+        ndef_aux = NULL;
3da501
         goto err;
3da501
+    }
3da501
+
3da501
+    /*
3da501
+     * We must not fail now because the callback has prepended additional
3da501
+     * BIOs to the chain
3da501
+     */
3da501
 
3da501
     ndef_aux->val = val;
3da501
     ndef_aux->it = it;
3da501
@@ -92,11 +116,11 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
3da501
     ndef_aux->boundary = sarg.boundary;
3da501
     ndef_aux->out = out;
3da501
 
3da501
-    BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
3da501
-
3da501
     return sarg.ndef_bio;
3da501
 
3da501
  err:
3da501
+    /* BIO_pop() is NULL safe */
3da501
+    (void)BIO_pop(pop_bio);
3da501
     BIO_free(asn_bio);
3da501
     OPENSSL_free(ndef_aux);
3da501
     return NULL;
3da501
-- 
3da501
2.39.1
3da501
3da501
From f596ec8a6f9f5fcfa8e46a73b60f78a609725294 Mon Sep 17 00:00:00 2001
3da501
From: Matt Caswell <matt@openssl.org>
3da501
Date: Wed, 14 Dec 2022 17:15:18 +0000
3da501
Subject: [PATCH 07/18] Check CMS failure during BIO setup with -stream is
3da501
 handled correctly
3da501
3da501
Test for the issue fixed in the previous commit
3da501
3da501
Reviewed-by: Paul Dale <pauli@openssl.org>
3da501
Reviewed-by: Tomas Mraz <tomas@openssl.org>
3da501
---
3da501
 test/recipes/80-test_cms.t  | 15 +++++++++++++--
3da501
 test/smime-certs/badrsa.pem | 18 ++++++++++++++++++
3da501
 2 files changed, 31 insertions(+), 2 deletions(-)
3da501
 create mode 100644 test/smime-certs/badrsa.pem
3da501
3da501
diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t
3da501
index 610f1cbc51..fd53683e6b 100644
3da501
--- a/test/recipes/80-test_cms.t
3da501
+++ b/test/recipes/80-test_cms.t
3da501
@@ -13,7 +13,7 @@ use warnings;
3da501
 use POSIX;
3da501
 use File::Spec::Functions qw/catfile/;
3da501
 use File::Compare qw/compare_text compare/;
3da501
-use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file/;
3da501
+use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file with/;
3da501
 
3da501
 use OpenSSL::Test::Utils;
3da501
 
3da501
@@ -50,7 +50,7 @@ my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib)
3da501
 
3da501
 $no_rc2 = 1 if disabled("legacy");
3da501
 
3da501
-plan tests => 12;
3da501
+plan tests => 13;
3da501
 
3da501
 ok(run(test(["pkcs7_test"])), "test pkcs7");
3da501
 
3da501
@@ -972,3 +972,14 @@ ok(!run(app(['openssl', 'cms', '-verify',
3da501
 
3da501
     return "";
3da501
 }
3da501
+
3da501
+# Check that we get the expected failure return code
3da501
+with({ exit_checker => sub { return shift == 6; } },
3da501
+    sub {
3da501
+        ok(run(app(['openssl', 'cms', '-encrypt',
3da501
+                    '-in', srctop_file("test", "smcont.txt"),
3da501
+                    '-stream', '-recip',
3da501
+                    srctop_file("test/smime-certs", "badrsa.pem"),
3da501
+                   ])),
3da501
+            "Check failure during BIO setup with -stream is handled correctly");
3da501
+    });
3da501
diff --git a/test/smime-certs/badrsa.pem b/test/smime-certs/badrsa.pem
3da501
new file mode 100644
3da501
index 0000000000..f824fc2267
3da501
--- /dev/null
3da501
+++ b/test/smime-certs/badrsa.pem
3da501
@@ -0,0 +1,18 @@
3da501
+-----BEGIN CERTIFICATE-----
3da501
+MIIDbTCCAlWgAwIBAgIToTV4Z0iuK08vZP20oTh//hC8BDANBgkqhkiG9w0BAQ0FADAtMSswKQYD
3da501
+VfcDEyJTYW1wbGUgTEFNUFMgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTE5MTEyMDA2NTQxOFoY
3da501
+DzIwNTIwOTI3MDY1NDE4WjAZMRcwFQYDVQQDEw5BbGljZSBMb3ZlbGFjZTCCASIwDQYJKoZIhvcN
3da501
+AQEBBQADggEPADCCAQoCggEBALT0iehYOBY+TZp/T5K2KNI05Hwr+E3wP6XTvyi6WWyTgBK9LCOw
3da501
+I2juwdRrjFBmXkk7pWpjXwsA3A5GOtz0FpfgyC7OxsVcF7q4WHWZWleYXFKlQHJD73nQwXP968+A
3da501
+/3rBX7PhO0DBbZnfitOLPgPEwjTtdg0VQQ6Wz+CRQ/YbHPKaw7aRphZO63dKvIKp4cQVtkWQHi6s
3da501
+yTjGsgkLcLNau5LZDQUdsGV+SAo3nBdWCRYV+I65x8Kf4hCxqqmjV3d/2NKRu0BXnDe/N+iDz3X0
3da501
+zEoj0fqXgq4SWcC0nsG1lyyXt1TL270I6ATKRGJWiQVCCpDtc0NT6vdJ45bCSxgCAwEAAaOBlzCB
3da501
+lDAMBgNVHRMBAf8EAjAAMB4GA1UdEQQXMBWBE2FsaWNlQHNtaW1lLmV4YW1wbGUwEwYDVR0lBAww
3da501
+CgYIKwYBBQUHAwQwDwYDVR0PAQH/BAUDAwfAADAdBgNVHQ4EFgQUu/bMsi0dBhIcl64papAQ0yBm
3da501
+ZnMwHwYDVR0jBBgwFoAUeF8OWnjYa+RUcD2z3ez38fL6wEcwDQYJKoZIhvcNAQENBQADggEBABbW
3da501
+eonR6TMTckehDKNOabwaCIcekahAIL6l9tTzUX5ew6ufiAPlC6I/zQlmUaU0iSyFDG1NW14kNbFt
3da501
+5CAokyLhMtE4ASHBIHbiOp/ZSbUBTVYJZB61ot7w1/ol5QECSs08b8zrxIncf+t2DHGuVEy/Qq1d
3da501
+rBz8d4ay8zpqAE1tUyL5Da6ZiKUfWwZQXSI/JlbjQFzYQqTRDnzHWrg1xPeMTO1P2/cplFaseTiv
3da501
+yk4cYwOp/W9UAWymOZXF8WcJYCIUXkdcG/nEZxr057KlScrJmFXOoh7Y+8ON4iWYYcAfiNgpUFo/
3da501
+j8BAwrKKaFvdlZS9k1Ypb2+UQY75mKJE9Bg=
3da501
+-----END CERTIFICATE-----
3da501
-- 
3da501
2.39.1
3da501