Blame SOURCES/openssl-1.1.1-cve-2023-0215-BIO-UAF.patch

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