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

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