diff --git a/SOURCES/openssl-1.1.1-cve-2024-4741.patch b/SOURCES/openssl-1.1.1-cve-2024-4741.patch new file mode 100644 index 0000000..fa55db2 --- /dev/null +++ b/SOURCES/openssl-1.1.1-cve-2024-4741.patch @@ -0,0 +1,70 @@ +From adf9a23d1a95c8378a81b720012b2f80aff618e2 Mon Sep 17 00:00:00 2001 +From: Watson Ladd +Date: Wed, 24 Apr 2024 11:26:56 +0100 +Subject: [PATCH] Only free the read buffers if we're not using them + +If we're part way through processing a record, or the application has +not released all the records then we should not free our buffer because +they are still needed. + +CVE-2024-4741 + +Reviewed-by: Tomas Mraz +Reviewed-by: Neil Horman +Reviewed-by: Matt Caswell +(Merged from https://github.com/openssl/openssl/pull/24395) +--- + ssl/record/rec_layer_s3.c | 9 +++++++++ + ssl/record/record.h | 1 + + ssl/ssl_lib.c | 3 +++ + 3 files changed, 13 insertions(+) + +diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c +index b2a7a47..7a67fd3 100644 +--- a/ssl/record/rec_layer_s3.c ++++ b/ssl/record/rec_layer_s3.c +@@ -80,6 +80,15 @@ int RECORD_LAYER_read_pending(const RECORD_LAYER *rl) + return SSL3_BUFFER_get_left(&rl->rbuf) != 0; + } + ++int RECORD_LAYER_data_present(const RECORD_LAYER *rl) ++{ ++ if (rl->rstate == SSL_ST_READ_BODY) ++ return 1; ++ if (RECORD_LAYER_processed_read_pending(rl)) ++ return 1; ++ return 0; ++} ++ + /* Checks if we have decrypted unread record data pending */ + int RECORD_LAYER_processed_read_pending(const RECORD_LAYER *rl) + { +diff --git a/ssl/record/record.h b/ssl/record/record.h +index af56206..513ab39 100644 +--- a/ssl/record/record.h ++++ b/ssl/record/record.h +@@ -197,6 +197,7 @@ void RECORD_LAYER_release(RECORD_LAYER *rl); + int RECORD_LAYER_read_pending(const RECORD_LAYER *rl); + int RECORD_LAYER_processed_read_pending(const RECORD_LAYER *rl); + int RECORD_LAYER_write_pending(const RECORD_LAYER *rl); ++int RECORD_LAYER_data_present(const RECORD_LAYER *rl); + void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl); + void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl); + int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl); +diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c +index 21e6c45..82236d8 100644 +--- a/ssl/ssl_lib.c ++++ b/ssl/ssl_lib.c +@@ -5209,6 +5209,9 @@ int SSL_free_buffers(SSL *ssl) + if (RECORD_LAYER_read_pending(rl) || RECORD_LAYER_write_pending(rl)) + return 0; + ++ if (RECORD_LAYER_data_present(rl)) ++ return 0; ++ + RECORD_LAYER_release(rl); + return 1; + } +-- +2.54.0 + diff --git a/SOURCES/openssl-1.1.1-cve-2026-45447.patch b/SOURCES/openssl-1.1.1-cve-2026-45447.patch new file mode 100644 index 0000000..f6e9e2a --- /dev/null +++ b/SOURCES/openssl-1.1.1-cve-2026-45447.patch @@ -0,0 +1,260 @@ +From 4ae990ae9c7f47ac214527dc5685e5df0c82d6b9 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Tue, 2 Jun 2026 14:55:02 +0200 +Subject: [PATCH] Fix double-free of caller-owned BIO in PKCS7_verify + +When PKCS7_dataInit creates no filter BIOs (e.g. empty digestAlgorithms +SET), it returns p7bio pointing directly to the caller's indata BIO. +The cleanup code in PKCS7_verify then frees indata via BIO_free_all(p7bio), +leaving the caller with a dangling pointer and causing a double-free +when the caller frees its own BIO. + +Guard BIO_free_all with a check that p7bio is not the caller's indata BIO. + +Add a regression test using a crafted S/MIME message with an empty +digestAlgorithms SET to verify the fix. + +Co-Authored-By: Claude Opus 4.6 +--- + crypto/pkcs7/pk7_smime.c | 5 +- + test/build.info | 7 +- + test/pkcs7_verify_test.c | 104 ++++++++++++++++++ + test/recipes/25-test_pkcs7_verify.t | 20 ++++ + .../pkcs7-empty-digest-set.eml | 45 ++++++++ + 5 files changed, 179 insertions(+), 2 deletions(-) + create mode 100644 test/pkcs7_verify_test.c + create mode 100644 test/recipes/25-test_pkcs7_verify.t + create mode 100644 test/recipes/25-test_pkcs7_verify_data/pkcs7-empty-digest-set.eml + +diff --git a/crypto/pkcs7/pk7_smime.c b/crypto/pkcs7/pk7_smime.c +index a95db62178..3e3ceda3cf 100644 +--- a/crypto/pkcs7/pk7_smime.c ++++ b/crypto/pkcs7/pk7_smime.c +@@ -363,8 +363,11 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, + if (tmpin == indata) { + if (indata) + BIO_pop(p7bio); ++ if (p7bio != indata) ++ BIO_free_all(p7bio); ++ } else { ++ BIO_free_all(p7bio); + } +- BIO_free_all(p7bio); + sk_X509_free(signers); + return ret; + } +diff --git a/test/build.info b/test/build.info +index 6357a7f2fe..648be6bbfc 100644 +--- a/test/build.info ++++ b/test/build.info +@@ -51,7 +51,8 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN + recordlentest drbgtest drbg_cavs_test sslbuffertest \ + time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \ + servername_test ocspapitest rsa_mp_test fatalerrtest tls13ccstest \ +- sysdefaulttest errtest ssl_ctx_test gosttest ++ sysdefaulttest errtest ssl_ctx_test gosttest \ ++ pkcs7_verify_test + + SOURCE[versions]=versions.c + INCLUDE[versions]=../include +@@ -574,6 +575,10 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN + INCLUDE[ssl_ctx_test]=../include + DEPEND[ssl_ctx_test]=../libcrypto ../libssl libtestutil.a + ++ SOURCE[pkcs7_verify_test]=pkcs7_verify_test.c ++ INCLUDE[pkcs7_verify_test]=../include ++ DEPEND[pkcs7_verify_test]=../libcrypto libtestutil.a ++ + {- + use File::Spec::Functions; + use File::Basename; +diff --git a/test/pkcs7_verify_test.c b/test/pkcs7_verify_test.c +new file mode 100644 +index 0000000000..932c2589ae +--- /dev/null ++++ b/test/pkcs7_verify_test.c +@@ -0,0 +1,104 @@ ++/* ++ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. ++ * ++ * Licensed under the OpenSSL license (the "License"). You may not use ++ * this file except in compliance with the License. You can obtain a copy ++ * in the file LICENSE in the source distribution or at ++ * https://www.openssl.org/source/license.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include "testutil.h" ++ ++static const char *emlfile; ++ ++/* ++ * Regression test for a double-free of the caller-owned indata BIO in ++ * PKCS7_verify. When the PKCS7 digestAlgorithms SET is empty, ++ * PKCS7_dataInit creates no digest filter BIOs and returns p7bio == indata. ++ * The cleanup code then frees the caller's BIO via BIO_free_all(p7bio). ++ * ++ * The test uses a crafted S/MIME message whose PKCS7 signature has an empty ++ * digestAlgorithms SET. The detached content is re-wrapped through a ++ * file-backed BIO to bypass the tmpin memory-BIO optimisation in ++ * PKCS7_verify (which would mask the bug). ++ */ ++static int test_pkcs7_verify_empty_md_algs(void) ++{ ++ int ret = 0; ++ BIO *bio_eml = NULL; ++ BIO *indata_mem = NULL; ++ BIO *indata = NULL; ++ PKCS7 *p7 = NULL; ++ char *mem_ptr = NULL; ++ long mem_len; ++ FILE *tmpf = NULL; ++ ++ if (!TEST_ptr(bio_eml = BIO_new_file(emlfile, "r"))) ++ goto err; ++ ++ if (!TEST_ptr(p7 = SMIME_read_PKCS7(bio_eml, &indata_mem))) ++ goto err; ++ ++ /* Confirm the test data has an empty digestAlgorithms SET */ ++ if (!TEST_int_eq(sk_X509_ALGOR_num(p7->d.sign->md_algs), 0)) ++ goto err; ++ ++ /* ++ * Re-wrap content through a file BIO so BIO_method_type != BIO_TYPE_MEM. ++ * This forces tmpin == indata in PKCS7_verify, hitting the vulnerable path. ++ */ ++ mem_len = BIO_get_mem_data(indata_mem, &mem_ptr); ++ if (!TEST_ptr(tmpf = tmpfile())) ++ goto err; ++ if (fwrite(mem_ptr, 1, mem_len, tmpf) != (size_t)mem_len) { ++ fclose(tmpf); ++ TEST_error("failed to write to temp file"); ++ goto err; ++ } ++ fflush(tmpf); ++ rewind(tmpf); ++ if (!TEST_ptr(indata = BIO_new_fp(tmpf, BIO_CLOSE))) { ++ fclose(tmpf); ++ goto err; ++ } ++ ++ /* ++ * NOVERIFY: skip cert chain validation ++ * NOSIGS: skip signature verification ++ * We only care about the BIO lifecycle, not cryptographic validity. ++ */ ++ PKCS7_verify(p7, NULL, NULL, indata, NULL, ++ PKCS7_NOVERIFY | PKCS7_NOSIGS); ++ ++ /* ++ * If the bug is present, indata has already been freed by PKCS7_verify. ++ * BIO_free will crash (use-after-free / double-free). Under ASan this ++ * is detected reliably; without ASan it may silently corrupt the heap. ++ */ ++ BIO_free(indata); ++ indata = NULL; ++ ++ ret = 1; ++ ++err: ++ BIO_free(indata); ++ BIO_free(indata_mem); ++ PKCS7_free(p7); ++ BIO_free(bio_eml); ++ return ret; ++} ++ ++int setup_tests(void) ++{ ++ if (!TEST_ptr(emlfile = test_get_argument(0))) { ++ TEST_note("usage: pkcs7_verify_test "); ++ return 0; ++ } ++ ++ ADD_TEST(test_pkcs7_verify_empty_md_algs); ++ return 1; ++} +diff --git a/test/recipes/25-test_pkcs7_verify.t b/test/recipes/25-test_pkcs7_verify.t +new file mode 100644 +index 0000000000..7666467f8c +--- /dev/null ++++ b/test/recipes/25-test_pkcs7_verify.t +@@ -0,0 +1,20 @@ ++#! /usr/bin/env perl ++# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. ++# ++# Licensed under the OpenSSL license (the "License"). You may not use ++# this file except in compliance with the License. You can obtain a copy ++# in the file LICENSE in the source distribution or at ++# https://www.openssl.org/source/license.html ++ ++use strict; ++use warnings; ++ ++use OpenSSL::Test qw/:DEFAULT data_file/; ++ ++setup("test_pkcs7_verify"); ++ ++plan tests => 1; ++ ++ok(run(test(["pkcs7_verify_test", ++ data_file("pkcs7-empty-digest-set.eml")])), ++ "PKCS7_verify with empty digestAlgorithms does not double-free indata"); +diff --git a/test/recipes/25-test_pkcs7_verify_data/pkcs7-empty-digest-set.eml b/test/recipes/25-test_pkcs7_verify_data/pkcs7-empty-digest-set.eml +new file mode 100644 +index 0000000000..a6db2c38ad +--- /dev/null ++++ b/test/recipes/25-test_pkcs7_verify_data/pkcs7-empty-digest-set.eml +@@ -0,0 +1,45 @@ ++MIME-Version: 1.0 ++Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----E0314CC5D732C92AE2D7A3BACDCDCFCE" ++ ++This is an S/MIME signed message ++ ++------E0314CC5D732C92AE2D7A3BACDCDCFCE ++This is the content to be signed. ++ ++------E0314CC5D732C92AE2D7A3BACDCDCFCE ++Content-Type: application/x-pkcs7-signature; name="smime.p7s" ++Content-Transfer-Encoding: base64 ++Content-Disposition: attachment; filename="smime.p7s" ++ ++MIIFWgYJKoZIhvcNAQcCoIIFSzCCBUcCAQExADALBgkqhkiG9w0BBwGgggLuMIIC ++6jCCAdKgAwIBAgIUL5E46FxyhsT7C3G1NS27OtR7XAowDQYJKoZIhvcNAQELBQAw ++FTETMBEGA1UEAwwKUG9DIFNpZ25lcjAeFw0yNjA1MDgxMDIwNDhaFw0yNzA1MDgx ++MDIwNDhaMBUxEzARBgNVBAMMClBvQyBTaWduZXIwggEiMA0GCSqGSIb3DQEBAQUA ++A4IBDwAwggEKAoIBAQDSSu/gupmIlclvmTMHiqOrCqmB8NRTjAMoI//MPJrnFXYp ++FjDPMk7Y/kCcHztudaIvADkowaFtOm4oMinQFhjwCNCo5K5WrrlAitnpcd5QH2nA ++iVZXjjohQUJEd7n33AGqTwo5EGaCK+alAZL7tA7bdhNi/aZ33L3bUNYqoHbXiNsE ++u1tj8frLfIjduOt0TMPSOrrFjjEsrL3T3tg+HmxpalDHz7E6o9zJu0wlk8bcR2Xk ++mpX8RdYCu7K9m39N1F2WKa9WJh24NQLpWRfwD213jaIFK2EXy/XHePDUeiMYtVOV ++oovCSmY7OqowupA7J+4dcsnRjFqgZECctHhAfk+PAgMBAAGjMjAwMB0GA1UdDgQW ++BBRZlupXNYq4fny0SE76sr/CdQ2DUTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 ++DQEBCwUAA4IBAQANOlttTWVz620JNTrPzhiR4x9+5UiF4GSqv8BRJQFj3Xh7fsUp +++3GDs9M27f4FVh3utJsjt7Sa9ZWLpBVdgjGBwGLAtPsoYMjhnUgZTUvwEk5+aXyv ++zJxn4I7mMbDhlNCMHcVtGdtA+2UOEuvdGfuEilpzPsV8DzM1K3xU5bSWoo0BRFKK ++srHkyEfxCFPAQOcX80ZbMO6zdcXeJjC6mQXGqy2aqeQob0vuSZJ7QHZBlRjY5YHR ++wWlIqG8G3Eist16iTqdX2PQFZT1/QAEQ/LnXARTUUjUroccdci8YNASoeHDpcjRL ++MBrN+QBNZVt5qLhDogwZb2ZwqKfZ8Aqg3oAkMYICPzCCAjsCAQEwLTAVMRMwEQYD ++VQQDDApQb0MgU2lnbmVyAhQvkTjoXHKGxPsLcbU1Lbs61HtcCjANBglghkgBZQME ++AgEFAKCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP ++Fw0yNjA1MDgxMDIwNDhaMC8GCSqGSIb3DQEJBDEiBCAvyoHfycLqb8UzVPizy1uA ++o3h7tza3HebeiJaSnpIJHzB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjAL ++BglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMC ++AgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkq ++hkiG9w0BAQEFAASCAQBIpl7U2j4YiU1vdZHyx2dCK41ZahtTVOB4RVJcrmopgans ++fICdkSTfb0dVqc13++bYn4i1b2R2os5YIkoGxdrM5aZB7KF9r1xwgrendTF4/BwP ++gQq2khNtKebv9Yr0kOPynFIsgx5BHk99wrzfwidJUFuJJgQ9W0YOf7EGkbnZvPT+ ++hV0aeLmJAb5jjWhbDciqUjR3O23JQhzVj4U3vo2TeN7VYmNJsX+fA4sZzIbYSei9 ++ps7GZruiRcKgqgUj1l8HjIGMHqd9lccchk/BYyAGxAbgGisntvfJdPZO09wG8rHh ++eS6FYkkXAKBO49WbhE9aVLJH0zgA6gTfyEvOOOS1 ++ ++------E0314CC5D732C92AE2D7A3BACDCDCFCE-- ++ +-- +2.54.0 + diff --git a/SOURCES/openssl-1.1.1-pkcs1-implicit-rejection.patch b/SOURCES/openssl-1.1.1-pkcs1-implicit-rejection.patch index 24041fb..0c223d7 100644 --- a/SOURCES/openssl-1.1.1-pkcs1-implicit-rejection.patch +++ b/SOURCES/openssl-1.1.1-pkcs1-implicit-rejection.patch @@ -1109,6 +1109,14 @@ --- openssl-1.1.1k/crypto/pkcs7/pk7_doit.c.pkcs1-implicit-rejection 2021-03-25 14:28:38.000000000 +0100 +++ openssl-1.1.1k/crypto/pkcs7/pk7_doit.c 2023-11-17 17:29:02.922553639 +0100 +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + @@ -159,6 +159,13 @@ static int pkcs7_decrypt_rinfo(unsigned goto err; } diff --git a/SPECS/openssl.spec b/SPECS/openssl.spec index 90f825b..d758705 100644 --- a/SPECS/openssl.spec +++ b/SPECS/openssl.spec @@ -22,7 +22,7 @@ Summary: Utilities from the general purpose cryptography library with TLS implementation Name: openssl Version: 1.1.1k -Release: 15%{?dist} +Release: 16%{?dist} Epoch: 1 # We have to remove certain patented algorithms from the openssl source # tarball with the hobble-openssl script which is included below. @@ -108,6 +108,8 @@ Patch111: openssl-1.1.1-ticket_lifetime_hint.patch # Fix for CVE-2025-69419 (next two) Patch112: openssl-1.1.1-hardening-from-openssl-3.0.1.patch Patch113: openssl-1.1.1-cve-2025-69419.patch +Patch114: openssl-1.1.1-cve-2026-45447.patch +Patch115: openssl-1.1.1-cve-2024-4741.patch License: OpenSSL and ASL 2.0 URL: http://www.openssl.org/ @@ -246,6 +248,8 @@ cp %{SOURCE13} test/ %patch -P111 -p1 -b .ticket_lifetime_hint %patch -P112 -p1 -b .cve-2025-69419-1 %patch -P113 -p1 -b .cve-2025-69419-2 +%patch -P114 -p1 -b .cve-2026-45447 +%patch -P115 -p1 -b .cve-2024-4741 %build # Figure out which flags we want to use. @@ -529,6 +533,12 @@ export LD_LIBRARY_PATH %postun libs -p /sbin/ldconfig %changelog +* Mon Jun 01 2026 Dmitry Belyavskiy - 1:1.1.1k-16 +- Fix CVE-2026-45447: Heap Use-After-Free in OpenSSL PKCS7_verify() + Resolves: RHEL-180978 +- Fix CVE-2024-4741: Use After Free with SSL_free_buffers + Resolves: RHEL-180983 + * Thu Feb 12 2026 Antonio Vieiro - 1:1.1.1k-15 - Fix CVE-2025-69419: Arbitrary code execution due to out-of-bounds write in PKCS#12 processing ticket_lifetime_hint exceed 1 week in TLSv1.3 and breaks compliant clients