From b88934109683d1d4982deb35483f06705389343e Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 8 Feb 2023 11:52:44 +0100 Subject: [PATCH] Fixed Use-after-free following BIO_new_NDEF Resolves: CVE-2023-0215 --- 0104-CVE-2023-0215-UAF-bio.patch | 187 +++++++++++++++++++++++++++++++ openssl.spec | 3 + 2 files changed, 190 insertions(+) create mode 100644 0104-CVE-2023-0215-UAF-bio.patch diff --git a/0104-CVE-2023-0215-UAF-bio.patch b/0104-CVE-2023-0215-UAF-bio.patch new file mode 100644 index 0000000..4140219 --- /dev/null +++ b/0104-CVE-2023-0215-UAF-bio.patch @@ -0,0 +1,187 @@ +From 8818064ce3c3c0f1b740a5aaba2a987e75bfbafd Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Wed, 14 Dec 2022 16:18:14 +0000 +Subject: [PATCH 06/18] 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. + +Reviewed-by: Paul Dale +Reviewed-by: Tomas Mraz +--- + crypto/asn1/bio_ndef.c | 40 ++++++++++++++++++++++++++++++++-------- + 1 file changed, 32 insertions(+), 8 deletions(-) + +diff --git a/crypto/asn1/bio_ndef.c b/crypto/asn1/bio_ndef.c +index d94e3a3644..b9df3a7a47 100644 +--- a/crypto/asn1/bio_ndef.c ++++ b/crypto/asn1/bio_ndef.c +@@ -49,13 +49,19 @@ static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg); + static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, + void *parg); + +-/* unfortunately cannot constify this due to CMS_stream() and PKCS7_stream() */ ++/* ++ * 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; + BIO *asn_bio = NULL; + const ASN1_AUX *aux = it->funcs; + ASN1_STREAM_ARG sarg; ++ BIO *pop_bio = NULL; + + if (!aux || !aux->asn1_cb) { + ERR_raise(ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED); +@@ -70,21 +76,39 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) + 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); ++ if (BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free) <= 0 ++ || BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free) <= 0 ++ || BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux) <= 0) ++ goto err; + + /* +- * Now let callback prepends 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.ndef_bio = NULL; + sarg.boundary = NULL; + +- if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) ++ /* ++ * 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 is now owned by asn_bio so we must not free it in the err ++ * clean up block ++ */ ++ ndef_aux = NULL; + goto err; ++ } ++ ++ /* ++ * We must not fail now because the callback has prepended additional ++ * BIOs to the chain ++ */ + + ndef_aux->val = val; + ndef_aux->it = it; +@@ -92,11 +116,11 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) + ndef_aux->boundary = sarg.boundary; + ndef_aux->out = out; + +- BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux); +- + 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; +-- +2.39.1 + +From f596ec8a6f9f5fcfa8e46a73b60f78a609725294 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Wed, 14 Dec 2022 17:15:18 +0000 +Subject: [PATCH 07/18] Check CMS failure during BIO setup with -stream is + handled correctly + +Test for the issue fixed in the previous commit + +Reviewed-by: Paul Dale +Reviewed-by: Tomas Mraz +--- + test/recipes/80-test_cms.t | 15 +++++++++++++-- + test/smime-certs/badrsa.pem | 18 ++++++++++++++++++ + 2 files changed, 31 insertions(+), 2 deletions(-) + create mode 100644 test/smime-certs/badrsa.pem + +diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t +index 610f1cbc51..fd53683e6b 100644 +--- a/test/recipes/80-test_cms.t ++++ b/test/recipes/80-test_cms.t +@@ -13,7 +13,7 @@ use warnings; + use POSIX; + use File::Spec::Functions qw/catfile/; + use File::Compare qw/compare_text compare/; +-use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file/; ++use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file with/; + + use OpenSSL::Test::Utils; + +@@ -50,7 +50,7 @@ my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib) + + $no_rc2 = 1 if disabled("legacy"); + +-plan tests => 12; ++plan tests => 13; + + ok(run(test(["pkcs7_test"])), "test pkcs7"); + +@@ -972,3 +972,14 @@ ok(!run(app(['openssl', 'cms', '-verify', + + return ""; + } ++ ++# Check that we get the expected failure return code ++with({ exit_checker => sub { return shift == 6; } }, ++ sub { ++ ok(run(app(['openssl', 'cms', '-encrypt', ++ '-in', srctop_file("test", "smcont.txt"), ++ '-stream', '-recip', ++ srctop_file("test/smime-certs", "badrsa.pem"), ++ ])), ++ "Check failure during BIO setup with -stream is handled correctly"); ++ }); +diff --git a/test/smime-certs/badrsa.pem b/test/smime-certs/badrsa.pem +new file mode 100644 +index 0000000000..f824fc2267 +--- /dev/null ++++ b/test/smime-certs/badrsa.pem +@@ -0,0 +1,18 @@ ++-----BEGIN CERTIFICATE----- ++MIIDbTCCAlWgAwIBAgIToTV4Z0iuK08vZP20oTh//hC8BDANBgkqhkiG9w0BAQ0FADAtMSswKQYD ++VfcDEyJTYW1wbGUgTEFNUFMgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTE5MTEyMDA2NTQxOFoY ++DzIwNTIwOTI3MDY1NDE4WjAZMRcwFQYDVQQDEw5BbGljZSBMb3ZlbGFjZTCCASIwDQYJKoZIhvcN ++AQEBBQADggEPADCCAQoCggEBALT0iehYOBY+TZp/T5K2KNI05Hwr+E3wP6XTvyi6WWyTgBK9LCOw ++I2juwdRrjFBmXkk7pWpjXwsA3A5GOtz0FpfgyC7OxsVcF7q4WHWZWleYXFKlQHJD73nQwXP968+A ++/3rBX7PhO0DBbZnfitOLPgPEwjTtdg0VQQ6Wz+CRQ/YbHPKaw7aRphZO63dKvIKp4cQVtkWQHi6s ++yTjGsgkLcLNau5LZDQUdsGV+SAo3nBdWCRYV+I65x8Kf4hCxqqmjV3d/2NKRu0BXnDe/N+iDz3X0 ++zEoj0fqXgq4SWcC0nsG1lyyXt1TL270I6ATKRGJWiQVCCpDtc0NT6vdJ45bCSxgCAwEAAaOBlzCB ++lDAMBgNVHRMBAf8EAjAAMB4GA1UdEQQXMBWBE2FsaWNlQHNtaW1lLmV4YW1wbGUwEwYDVR0lBAww ++CgYIKwYBBQUHAwQwDwYDVR0PAQH/BAUDAwfAADAdBgNVHQ4EFgQUu/bMsi0dBhIcl64papAQ0yBm ++ZnMwHwYDVR0jBBgwFoAUeF8OWnjYa+RUcD2z3ez38fL6wEcwDQYJKoZIhvcNAQENBQADggEBABbW ++eonR6TMTckehDKNOabwaCIcekahAIL6l9tTzUX5ew6ufiAPlC6I/zQlmUaU0iSyFDG1NW14kNbFt ++5CAokyLhMtE4ASHBIHbiOp/ZSbUBTVYJZB61ot7w1/ol5QECSs08b8zrxIncf+t2DHGuVEy/Qq1d ++rBz8d4ay8zpqAE1tUyL5Da6ZiKUfWwZQXSI/JlbjQFzYQqTRDnzHWrg1xPeMTO1P2/cplFaseTiv ++yk4cYwOp/W9UAWymOZXF8WcJYCIUXkdcG/nEZxr057KlScrJmFXOoh7Y+8ON4iWYYcAfiNgpUFo/ ++j8BAwrKKaFvdlZS9k1Ypb2+UQY75mKJE9Bg= ++-----END CERTIFICATE----- +-- +2.39.1 + diff --git a/openssl.spec b/openssl.spec index 0bf09f2..ef22b31 100644 --- a/openssl.spec +++ b/openssl.spec @@ -159,6 +159,7 @@ Patch92: 0092-provider-improvements.patch Patch101: 0101-CVE-2022-4203-nc-match.patch Patch102: 0102-CVE-2022-4304-RSA-time-oracle.patch Patch103: 0103-CVE-2022-4450-pem-read-bio.patch +Patch104: 0104-CVE-2023-0215-UAF-bio.patch License: ASL 2.0 URL: http://www.openssl.org/ @@ -496,6 +497,8 @@ install -m644 %{SOURCE9} \ Resolves: CVE-2022-4304 - Fixed Double free after calling PEM_read_bio_ex Resolves: CVE-2022-4450 +- Fixed Use-after-free following BIO_new_NDEF + Resolves: CVE-2023-0215 * Wed Jan 11 2023 Clemens Lang - 1:3.0.7-4 - Disallow SHAKE in RSA-OAEP decryption in FIPS mode