From 5b2750bf68989b180fb287fd87825aa6cc7f2f34 Mon Sep 17 00:00:00 2001 From: Azure Linux Security Servicing Account Date: Mon, 13 Apr 2026 10:24:45 +0000 Subject: [PATCH 1/2] Patch osslsigncode for CVE-2026-39855, CVE-2026-39853, CVE-2025-70888 --- SPECS/osslsigncode/CVE-2025-70888.patch | 43 ++++++++ SPECS/osslsigncode/CVE-2026-39853.patch | 140 ++++++++++++++++++++++++ SPECS/osslsigncode/CVE-2026-39855.patch | 34 ++++++ SPECS/osslsigncode/osslsigncode.spec | 8 +- 4 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 SPECS/osslsigncode/CVE-2025-70888.patch create mode 100644 SPECS/osslsigncode/CVE-2026-39853.patch create mode 100644 SPECS/osslsigncode/CVE-2026-39855.patch diff --git a/SPECS/osslsigncode/CVE-2025-70888.patch b/SPECS/osslsigncode/CVE-2025-70888.patch new file mode 100644 index 00000000000..ee5f9992692 --- /dev/null +++ b/SPECS/osslsigncode/CVE-2025-70888.patch @@ -0,0 +1,43 @@ +From 13656398658c7911199eef7f64b21c4cf6bc5fa2 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Mon, 13 Apr 2026 10:13:41 +0000 +Subject: [PATCH] Add keyUsage digitalSignature validation for signer + certificate + +Verify that: +- extendedKeyUsage, if present, permits codeSigning (RFC 5280 section 4.2.1.12) +- keyUsage, if present, permits digitalSignature (RFC 5280 section 4.2.1.3) + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://patch-diff.githubusercontent.com/raw/mtrojnar/osslsigncode/pull/477.patch +--- + osslsigncode.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/osslsigncode.c b/osslsigncode.c +index 320980f..b1fcd7b 100644 +--- a/osslsigncode.c ++++ b/osslsigncode.c +@@ -1718,9 +1718,17 @@ static int verify_authenticode(FILE_FORMAT_CTX *ctx, PKCS7 *p7, time_t time, X50 + if (!crlok) + goto out; + } +- /* check extended key usage flag XKU_CODE_SIGN */ ++ /* ++ * Verify that: ++ * - extendedKeyUsage, if present, permits codeSigning (RFC 5280 section 4.2.1.12) ++ * - keyUsage, if present, permits digitalSignature (RFC 5280 section 4.2.1.3) ++ */ + if (!(X509_get_extended_key_usage(signer) & XKU_CODE_SIGN)) { +- printf("Unsupported Signer's certificate purpose XKU_CODE_SIGN\n"); ++ fprintf(stderr, "Signer certificate rejected: extendedKeyUsage does not permit codeSigning\n"); ++ goto out; ++ } ++ if (!(X509_get_key_usage(signer) & X509v3_KU_DIGITAL_SIGNATURE)) { ++ fprintf(stderr, "Signer certificate rejected: keyUsage does not permit digitalSignature\n"); + goto out; + } + +-- +2.45.4 + diff --git a/SPECS/osslsigncode/CVE-2026-39853.patch b/SPECS/osslsigncode/CVE-2026-39853.patch new file mode 100644 index 00000000000..d0d35599fb8 --- /dev/null +++ b/SPECS/osslsigncode/CVE-2026-39853.patch @@ -0,0 +1,140 @@ +From 05b4da29d5a6376da6542406839deb0888d08f27 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Mon, 13 Apr 2026 10:09:16 +0000 +Subject: [PATCH] Fixed buffer overflow while extracting msg digest + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/mtrojnar/osslsigncode/commit/cbee1e723c5a8547302bd841ad9943ed8144db68.patch +--- + cab.c | 6 +++--- + helpers.c | 28 ++++++++++++++++++++++++++++ + helpers.h | 2 ++ + msi.c | 6 +++--- + osslsigncode.c | 7 +++---- + pe.c | 6 +++--- + 6 files changed, 42 insertions(+), 13 deletions(-) + +diff --git a/cab.c b/cab.c +index cc8e745..f6547dd 100644 +--- a/cab.c ++++ b/cab.c +@@ -330,9 +330,9 @@ static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7) + const u_char *p = content_val->data; + SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length); + if (idc) { +- if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) { +- mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm); +- memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length); ++ if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) { ++ SpcIndirectDataContent_free(idc); ++ return 0; /* FAILED */ + } + SpcIndirectDataContent_free(idc); + } +diff --git a/helpers.c b/helpers.c +index 184fd29..24640e6 100644 +--- a/helpers.c ++++ b/helpers.c +@@ -503,6 +503,34 @@ SpcLink *spc_link_obsolete_get(void) + return link; + } + ++/* ++ * Safely extract digest from SpcIndirectDataContent ++ * [in] idc: parsed SpcIndirectDataContent ++ * [out] mdbuf: output buffer (must be EVP_MAX_MD_SIZE bytes) ++ * [out] mdtype: digest algorithm's NID ++ * [returns] -1 on error or digest length on success ++ */ ++int spc_extract_digest_safe(SpcIndirectDataContent *idc, ++ u_char *mdbuf, int *mdtype) ++{ ++ int digest_len; ++ ++ if (!idc || !idc->messageDigest || !idc->messageDigest->digest || ++ !idc->messageDigest->digestAlgorithm) { ++ fprintf(stderr, "Missing digest data\n"); ++ return -1; ++ } ++ digest_len = idc->messageDigest->digest->length; ++ if (digest_len <= 0 || digest_len > EVP_MAX_MD_SIZE) { ++ fprintf(stderr, "Invalid digest length: %d\n", digest_len); ++ return -1; ++ } ++ memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)digest_len); ++ *mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm); ++ return digest_len; ++} ++ ++ + /* + * Retrieve a decoded PKCS#7 structure + * [in] indata: mapped file +diff --git a/helpers.h b/helpers.h +index fa0c13c..d5c40df 100644 +--- a/helpers.h ++++ b/helpers.h +@@ -21,6 +21,8 @@ void print_hash(const char *descript1, const char *descript2, const u_char *hash + int is_content_type(PKCS7 *p7, const char *objid); + int pkcs7_set_data_content(PKCS7 *sig, BIO *hash, FILE_FORMAT_CTX *ctx); + SpcLink *spc_link_obsolete_get(void); ++int spc_extract_digest_safe(SpcIndirectDataContent *idc, ++ u_char *mdbuf, int *mdtype); + PKCS7 *pkcs7_get(char *indata, uint32_t sigpos, uint32_t siglen); + int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype); + +diff --git a/msi.c b/msi.c +index beadfc9..73c1f57 100644 +--- a/msi.c ++++ b/msi.c +@@ -470,9 +470,9 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7) + const u_char *p = content_val->data; + SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length); + if (idc) { +- if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) { +- mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm); +- memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length); ++ if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) { ++ SpcIndirectDataContent_free(idc); ++ return 0; /* FAILED */ + } + SpcIndirectDataContent_free(idc); + } +diff --git a/osslsigncode.c b/osslsigncode.c +index 044f015..320980f 100644 +--- a/osslsigncode.c ++++ b/osslsigncode.c +@@ -2220,10 +2220,9 @@ static int verify_member(FILE_FORMAT_CTX *ctx, CatalogAuthAttr *attribute) + ASN1_TYPE_free(content); + return 1; /* FAILED */ + } +- if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) { +- /* get a digest algorithm a message digest of the file from the content */ +- mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm); +- memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length); ++ if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) { ++ ASN1_TYPE_free(content); ++ return 1; /* FAILED */ + } + ASN1_TYPE_free(content); + if (mdtype == -1) { +diff --git a/pe.c b/pe.c +index c7fc67d..5b5c121 100644 +--- a/pe.c ++++ b/pe.c +@@ -320,9 +320,9 @@ static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7) + SpcIndirectDataContent_free(idc); + return 0; /* FAILED */ + } +- if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) { +- mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm); +- memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length); ++ if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) { ++ SpcIndirectDataContent_free(idc); ++ return 0; /* FAILED */ + } + SpcIndirectDataContent_free(idc); + } +-- +2.45.4 + diff --git a/SPECS/osslsigncode/CVE-2026-39855.patch b/SPECS/osslsigncode/CVE-2026-39855.patch new file mode 100644 index 00000000000..56297da1a88 --- /dev/null +++ b/SPECS/osslsigncode/CVE-2026-39855.patch @@ -0,0 +1,34 @@ +From aaa450ee64bb701c28941abc254e186dda2569ca Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Mon, 13 Apr 2026 09:54:18 +0000 +Subject: [PATCH] Fix header bounds validation in PE page hash calculation + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/mtrojnar/osslsigncode/commit/2a5409b7c4b6c6fad2b093531e8fea6cf08e1568.patch +--- + pe.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/pe.c b/pe.c +index c93daa6..c7fc67d 100644 +--- a/pe.c ++++ b/pe.c +@@ -959,6 +959,15 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) + printf("Corrupted headers size: 0x%08X\n", hdrsize); + return NULL; /* FAILED */ + } ++ /* Validate header bounds before performing BIO writes */ ++ { ++ size_t off = (size_t)ctx->pe_ctx->header_size + 160 + (size_t)ctx->pe_ctx->pe32plus * 16; ++ /* hdrsize must not be smaller than the end of data directories and must fit within a page */ ++ if (hdrsize < off || hdrsize > pagesize) { ++ printf("Corrupted headers size: 0x%08X\n", hdrsize); ++ return NULL; /* FAILED: header size out of bounds */ ++ } ++ } + /* SizeOfOptionalHeader is the size of the optional header, which is + * required for executable files, but for object files should be zero, + * and can't be bigger than the file */ +-- +2.45.4 + diff --git a/SPECS/osslsigncode/osslsigncode.spec b/SPECS/osslsigncode/osslsigncode.spec index 423183db9a5..144cb3dddc1 100644 --- a/SPECS/osslsigncode/osslsigncode.spec +++ b/SPECS/osslsigncode/osslsigncode.spec @@ -1,12 +1,15 @@ Summary: Verify and sign routines for PE binaries Name: osslsigncode Version: 2.7 -Release: 1%{?dist} +Release: 2%{?dist} License: MIT Group: Applications/System Vendor: Microsoft Corporation Distribution: Mariner Source0: https://github.com/mtrojnar/%{name}/archive/refs/tags/%{version}.tar.gz#/%{name}-%{version}.tar.gz +Patch0: CVE-2025-70888.patch +Patch1: CVE-2026-39853.patch +Patch2: CVE-2026-39855.patch BuildRequires: python3 BuildRequires: cmake BuildRequires: openssl-devel @@ -34,6 +37,9 @@ install -D -m 755 ./build/osslsigncode %{buildroot}%{_bindir}/osslsigncode %{_bindir}/osslsigncode %changelog +* Mon Apr 13 2026 Azure Linux Security Servicing Account - 2.7-2 +- Patch for CVE-2026-39855, CVE-2026-39853, CVE-2025-70888 + * Tue Feb 13 2024 Cameron Baird 2.7-1 - Original version for CBL-Mariner (license: MIT). - License verified From ff44c388c4d4c47b753671780510eba354883188 Mon Sep 17 00:00:00 2001 From: BinduSri-6522866 Date: Tue, 14 Apr 2026 13:57:26 +0000 Subject: [PATCH 2/2] Patch osslsigncode for CVE-2026-39856 & backported CVE-2026-39853 and CVE-2026-39855 --- SPECS/osslsigncode/CVE-2026-39853.patch | 22 +-- SPECS/osslsigncode/CVE-2026-39855.patch | 54 ++++-- SPECS/osslsigncode/CVE-2026-39856.patch | 247 ++++++++++++++++++++++++ SPECS/osslsigncode/osslsigncode.spec | 3 +- 4 files changed, 296 insertions(+), 30 deletions(-) create mode 100644 SPECS/osslsigncode/CVE-2026-39856.patch diff --git a/SPECS/osslsigncode/CVE-2026-39853.patch b/SPECS/osslsigncode/CVE-2026-39853.patch index d0d35599fb8..743c3c24077 100644 --- a/SPECS/osslsigncode/CVE-2026-39853.patch +++ b/SPECS/osslsigncode/CVE-2026-39853.patch @@ -3,16 +3,15 @@ From: AllSpark Date: Mon, 13 Apr 2026 10:09:16 +0000 Subject: [PATCH] Fixed buffer overflow while extracting msg digest -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/mtrojnar/osslsigncode/commit/cbee1e723c5a8547302bd841ad9943ed8144db68.patch +Upstream Patch reference: https://github.com/mtrojnar/osslsigncode/commit/cbee1e723c5a8547302bd841ad9943ed8144db68.patch --- cab.c | 6 +++--- - helpers.c | 28 ++++++++++++++++++++++++++++ + helpers.c | 27 +++++++++++++++++++++++++++ helpers.h | 2 ++ msi.c | 6 +++--- osslsigncode.c | 7 +++---- pe.c | 6 +++--- - 6 files changed, 42 insertions(+), 13 deletions(-) + 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/cab.c b/cab.c index cc8e745..f6547dd 100644 @@ -32,10 +31,10 @@ index cc8e745..f6547dd 100644 SpcIndirectDataContent_free(idc); } diff --git a/helpers.c b/helpers.c -index 184fd29..24640e6 100644 +index 184fd29..b42de60 100644 --- a/helpers.c +++ b/helpers.c -@@ -503,6 +503,34 @@ SpcLink *spc_link_obsolete_get(void) +@@ -503,6 +503,33 @@ SpcLink *spc_link_obsolete_get(void) return link; } @@ -65,7 +64,6 @@ index 184fd29..24640e6 100644 + *mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm); + return digest_len; +} -+ + /* * Retrieve a decoded PKCS#7 structure @@ -101,10 +99,10 @@ index beadfc9..73c1f57 100644 SpcIndirectDataContent_free(idc); } diff --git a/osslsigncode.c b/osslsigncode.c -index 044f015..320980f 100644 +index 6960fd8..f29a902 100644 --- a/osslsigncode.c +++ b/osslsigncode.c -@@ -2220,10 +2220,9 @@ static int verify_member(FILE_FORMAT_CTX *ctx, CatalogAuthAttr *attribute) +@@ -2228,10 +2228,9 @@ static int verify_member(FILE_FORMAT_CTX *ctx, CatalogAuthAttr *attribute) ASN1_TYPE_free(content); return 1; /* FAILED */ } @@ -113,13 +111,13 @@ index 044f015..320980f 100644 - mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm); - memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length); + if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) { -+ ASN1_TYPE_free(content); ++ SpcIndirectDataContent_free(idc); + return 1; /* FAILED */ } ASN1_TYPE_free(content); if (mdtype == -1) { diff --git a/pe.c b/pe.c -index c7fc67d..5b5c121 100644 +index c93daa6..d55bdf5 100644 --- a/pe.c +++ b/pe.c @@ -320,9 +320,9 @@ static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7) @@ -136,5 +134,5 @@ index c7fc67d..5b5c121 100644 SpcIndirectDataContent_free(idc); } -- -2.45.4 +2.43.0 diff --git a/SPECS/osslsigncode/CVE-2026-39855.patch b/SPECS/osslsigncode/CVE-2026-39855.patch index 56297da1a88..9452c425ea4 100644 --- a/SPECS/osslsigncode/CVE-2026-39855.patch +++ b/SPECS/osslsigncode/CVE-2026-39855.patch @@ -1,34 +1,54 @@ -From aaa450ee64bb701c28941abc254e186dda2569ca Mon Sep 17 00:00:00 2001 -From: AllSpark -Date: Mon, 13 Apr 2026 09:54:18 +0000 +From 2a5409b7c4b6c6fad2b093531e8fea6cf08e1568 Mon Sep 17 00:00:00 2001 +From: olszomal +Date: Mon, 9 Feb 2026 14:18:06 +0100 Subject: [PATCH] Fix header bounds validation in PE page hash calculation -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/mtrojnar/osslsigncode/commit/2a5409b7c4b6c6fad2b093531e8fea6cf08e1568.patch +Upstream Patch reference: https://github.com/mtrojnar/osslsigncode/commit/2a5409b7c4b6c6fad2b093531e8fea6cf08e1568.patch --- - pe.c | 9 +++++++++ - 1 file changed, 9 insertions(+) + pe.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pe.c b/pe.c -index c93daa6..c7fc67d 100644 +index d55bdf5..9b70b28 100644 --- a/pe.c +++ b/pe.c -@@ -959,6 +959,15 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) +@@ -921,11 +921,12 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) + uint32_t alignment, pagesize, hdrsize; + uint32_t rs, ro, l, lastpos = 0; + int pphlen, phlen, i, pi = 1; +- size_t written; ++ size_t written, off; + u_char *res, *zeroes; + char *sections; + const EVP_MD *md = EVP_get_digestbynid(phtype); + BIO *bhash; ++ uint32_t filebound; + + /* NumberOfSections indicates the size of the section table, + * which immediately follows the headers, can be up to 65535 under Vista and later */ +@@ -959,6 +960,12 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) printf("Corrupted headers size: 0x%08X\n", hdrsize); return NULL; /* FAILED */ } + /* Validate header bounds before performing BIO writes */ -+ { -+ size_t off = (size_t)ctx->pe_ctx->header_size + 160 + (size_t)ctx->pe_ctx->pe32plus * 16; -+ /* hdrsize must not be smaller than the end of data directories and must fit within a page */ -+ if (hdrsize < off || hdrsize > pagesize) { -+ printf("Corrupted headers size: 0x%08X\n", hdrsize); -+ return NULL; /* FAILED: header size out of bounds */ -+ } ++ off = ctx->pe_ctx->header_size + 160 + (size_t)ctx->pe_ctx->pe32plus * 16; ++ if (hdrsize < off || hdrsize > filebound) { ++ printf("Corrupted headers size: 0x%08X\n", hdrsize); ++ return NULL; /* FAILED: header too small */ + } /* SizeOfOptionalHeader is the size of the optional header, which is * required for executable files, but for object files should be zero, * and can't be bigger than the file */ +@@ -970,6 +977,9 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) + pphlen = 4 + EVP_MD_size(md); + phlen = pphlen * (3 + (int)nsections + (int)(ctx->pe_ctx->fileend / pagesize)); + ++ /* Determine the file boundary for section data validation */ ++ filebound = ctx->pe_ctx->sigpos ? ctx->pe_ctx->sigpos : ctx->pe_ctx->fileend; ++ + bhash = BIO_new(BIO_f_md()); + if (!BIO_set_md(bhash, md)) { + printf("Unable to set the message digest of BIO\n"); -- -2.45.4 +2.43.0 diff --git a/SPECS/osslsigncode/CVE-2026-39856.patch b/SPECS/osslsigncode/CVE-2026-39856.patch new file mode 100644 index 00000000000..75b513edeb1 --- /dev/null +++ b/SPECS/osslsigncode/CVE-2026-39856.patch @@ -0,0 +1,247 @@ +From 92f8761b4770f76a36731969b5040ce3b9a09570 Mon Sep 17 00:00:00 2001 +From: olszomal +Date: Fri, 6 Feb 2026 14:34:18 +0100 +Subject: [PATCH] Fix heap corruption in PE page hash calculation + +Upstream Patch reference: https://github.com/mtrojnar/osslsigncode/commit/92f8761b4770f76a36731969b5040ce3b9a09570.patch + +--- + pe.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 121 insertions(+), 28 deletions(-) + +diff --git a/pe.c b/pe.c +index 9b70b28..dbea020 100644 +--- a/pe.c ++++ b/pe.c +@@ -920,14 +920,25 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) + uint16_t nsections, opthdr_size; + uint32_t alignment, pagesize, hdrsize; + uint32_t rs, ro, l, lastpos = 0; +- int pphlen, phlen, i, pi = 1; +- size_t written, off; +- u_char *res, *zeroes; ++ int mdlen, pphlen, phlen, i, pi = 1; ++ size_t written, off, sect_off, sect_tbl, need; ++ u_char *res = NULL, *zeroes = NULL; + char *sections; + const EVP_MD *md = EVP_get_digestbynid(phtype); +- BIO *bhash; ++ BIO *bhash = NULL; + uint32_t filebound; + ++ if (rphlen == NULL || ctx == NULL || ctx->options == NULL || ctx->pe_ctx == NULL ++ || ctx->options->indata == NULL) ++ return NULL; ++ ++ if (md == NULL) ++ return NULL; ++ ++ mdlen = EVP_MD_size(md); ++ if (mdlen <= 0) ++ return NULL; ++ + /* NumberOfSections indicates the size of the section table, + * which immediately follows the headers, can be up to 65535 under Vista and later */ + nsections = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 6); +@@ -974,19 +985,36 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) + printf("Corrupted optional header size: 0x%08X\n", opthdr_size); + return NULL; /* FAILED */ + } +- pphlen = 4 + EVP_MD_size(md); ++ pphlen = 4 + mdlen; + phlen = pphlen * (3 + (int)nsections + (int)(ctx->pe_ctx->fileend / pagesize)); + + /* Determine the file boundary for section data validation */ + filebound = ctx->pe_ctx->sigpos ? ctx->pe_ctx->sigpos : ctx->pe_ctx->fileend; + ++ /* Validate section table bounds before reading section headers */ ++ sect_off = (size_t)ctx->pe_ctx->header_size + 24u + (size_t)opthdr_size; ++ sect_tbl = (size_t)nsections * 40u; ++ ++ if (sect_off > (size_t)filebound || sect_tbl > (size_t)filebound - sect_off) { ++ fprintf(stderr, "Section table out of bounds: off=%zu size=%zu filebound=%u\n", ++ sect_off, sect_tbl, filebound); ++ return NULL; /* FAILED */ ++ } ++ sections = (char *)ctx->options->indata + sect_off; ++ + bhash = BIO_new(BIO_f_md()); ++ if (bhash == NULL) ++ return NULL; ++ + if (!BIO_set_md(bhash, md)) { + printf("Unable to set the message digest of BIO\n"); + BIO_free_all(bhash); + return NULL; /* FAILED */ + } +- BIO_push(bhash, BIO_new(BIO_s_null())); ++ if (BIO_push(bhash, BIO_new(BIO_s_null())) == NULL) { ++ BIO_free_all(bhash); ++ return NULL; ++ } + if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written) + || written != ctx->pe_ctx->header_size + 88) { + BIO_free_all(bhash); +@@ -998,36 +1026,76 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) + BIO_free_all(bhash); + return NULL; /* FAILED */ + } +- if (!BIO_write_ex(bhash, +- ctx->options->indata + ctx->pe_ctx->header_size + 160 + ctx->pe_ctx->pe32plus*16, +- hdrsize - (ctx->pe_ctx->header_size + 160 + ctx->pe_ctx->pe32plus*16), &written) +- || written != hdrsize - (ctx->pe_ctx->header_size + 160 + ctx->pe_ctx->pe32plus*16)) { ++ off = ctx->pe_ctx->header_size + 160 + (size_t)ctx->pe_ctx->pe32plus * 16; ++ if (hdrsize < off) { ++ BIO_free_all(bhash); ++ return NULL; /* FAILED: header too small */ ++ } ++ if (!BIO_write_ex(bhash, ctx->options->indata + off, (size_t)hdrsize - off, &written) ++ || written != hdrsize - off) { + BIO_free_all(bhash); + return NULL; /* FAILED */ + } ++ if (pagesize < hdrsize) { ++ BIO_free_all(bhash); ++ return NULL; /* FAILED: header larger than page */ ++ } + zeroes = OPENSSL_zalloc((size_t)pagesize); +- if (!BIO_write_ex(bhash, zeroes, pagesize - hdrsize, &written) +- || written != pagesize - hdrsize) { ++ if (zeroes == NULL) { ++ BIO_free_all(bhash); ++ return NULL; /* FAILED */ ++ } ++ if (!BIO_write_ex(bhash, zeroes, (size_t)pagesize - (size_t)hdrsize, &written) ++ || written != (size_t)pagesize - (size_t)hdrsize) { + BIO_free_all(bhash); + OPENSSL_free(zeroes); + return NULL; /* FAILED */ + } + res = OPENSSL_malloc((size_t)phlen); ++ if (res == NULL) { ++ BIO_free_all(bhash); ++ OPENSSL_free(zeroes); ++ return NULL; /* FAILED */ ++ } + memset(res, 0, 4); +- BIO_gets(bhash, (char*)res + 4, EVP_MD_size(md)); ++ if (BIO_gets(bhash, (char *)res + 4, mdlen) != mdlen) { ++ BIO_free_all(bhash); ++ OPENSSL_free(zeroes); ++ OPENSSL_free(res); ++ return NULL; /* FAILED */ ++ } + BIO_free_all(bhash); +- sections = ctx->options->indata + ctx->pe_ctx->header_size + 24 + opthdr_size; +- for (i=0; i= UINT32_MAX) { ++ if (rs == 0) { + sections += 40; + continue; + } +- for (l=0; l (size_t)phlen) { ++ fprintf(stderr, "Page hash buffer overflow prevented: pi=%d need=%zu phlen=%d\n", ++ pi, need, phlen); ++ OPENSSL_free(zeroes); ++ OPENSSL_free(res); ++ return NULL; /* FAILED */ ++ } ++ ++ PUT_UINT32_LE(ro + l, res + (size_t)pi * (size_t)pphlen); ++ + bhash = BIO_new(BIO_f_md()); ++ if (bhash == NULL) { ++ OPENSSL_free(zeroes); ++ OPENSSL_free(res); ++ return NULL; ++ } ++ + if (!BIO_set_md(bhash, md)) { + printf("Unable to set the message digest of BIO\n"); + BIO_free_all(bhash); +@@ -1035,17 +1103,24 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) + OPENSSL_free(res); + return NULL; /* FAILED */ + } +- BIO_push(bhash, BIO_new(BIO_s_null())); +- if (rs - l < pagesize) { +- if (!BIO_write_ex(bhash, ctx->options->indata + ro + l, rs - l, &written) +- || written != rs - l) { ++ if (BIO_push(bhash, BIO_new(BIO_s_null())) == NULL) { ++ BIO_free_all(bhash); ++ OPENSSL_free(zeroes); ++ OPENSSL_free(res); ++ return NULL; ++ } ++ if (l < rs && rs - l < pagesize) { ++ size_t tail = (size_t)(rs - l); ++ ++ if (!BIO_write_ex(bhash, ctx->options->indata + ro + l, tail, &written) ++ || written != tail) { + BIO_free_all(bhash); + OPENSSL_free(zeroes); + OPENSSL_free(res); + return NULL; /* FAILED */ + } +- if (!BIO_write_ex(bhash, zeroes, pagesize - (rs - l), &written) +- || written != pagesize - (rs - l)) { ++ if (!BIO_write_ex(bhash, zeroes, pagesize - tail, &written) ++ || written != pagesize - tail) { + BIO_free_all(bhash); + OPENSSL_free(zeroes); + OPENSSL_free(res); +@@ -1060,17 +1135,35 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype) + return NULL; /* FAILED */ + } + } +- BIO_gets(bhash, (char*)res + pi*pphlen + 4, EVP_MD_size(md)); ++ if (BIO_gets(bhash, (char *)res + (size_t)pi * (size_t)pphlen + 4, mdlen) != mdlen) { ++ BIO_free_all(bhash); ++ OPENSSL_free(zeroes); ++ OPENSSL_free(res); ++ return NULL; /* FAILED */ ++ } + BIO_free_all(bhash); ++ bhash = NULL; + } + lastpos = ro + rs; + sections += 40; + } +- PUT_UINT32_LE(lastpos, res + pi*pphlen); +- memset(res + pi*pphlen + 4, 0, (size_t)EVP_MD_size(md)); ++ /* Final entry */ ++ need = (size_t)(pi + 1) * (size_t)pphlen; ++ ++ if (need > (size_t)phlen) { ++ fprintf(stderr, "Page hash buffer overflow prevented at final entry: pi=%d need=%zu phlen=%d\n", ++ pi, need, phlen); ++ OPENSSL_free(zeroes); ++ OPENSSL_free(res); ++ return NULL; /* FAILED */ ++ } ++ ++ PUT_UINT32_LE(lastpos, res + (size_t)pi * (size_t)pphlen); ++ memset(res + (size_t)pi * (size_t)pphlen + 4, 0, (size_t)mdlen); + pi++; ++ + OPENSSL_free(zeroes); +- *rphlen = pi*pphlen; ++ *rphlen = pi * pphlen; + return res; + } + +-- +2.43.0 + diff --git a/SPECS/osslsigncode/osslsigncode.spec b/SPECS/osslsigncode/osslsigncode.spec index 144cb3dddc1..5e341758bc5 100644 --- a/SPECS/osslsigncode/osslsigncode.spec +++ b/SPECS/osslsigncode/osslsigncode.spec @@ -10,6 +10,7 @@ Source0: https://github.com/mtrojnar/%{name}/archive/refs/tags/%{version} Patch0: CVE-2025-70888.patch Patch1: CVE-2026-39853.patch Patch2: CVE-2026-39855.patch +Patch3: CVE-2026-39856.patch BuildRequires: python3 BuildRequires: cmake BuildRequires: openssl-devel @@ -38,7 +39,7 @@ install -D -m 755 ./build/osslsigncode %{buildroot}%{_bindir}/osslsigncode %changelog * Mon Apr 13 2026 Azure Linux Security Servicing Account - 2.7-2 -- Patch for CVE-2026-39855, CVE-2026-39853, CVE-2025-70888 +- Patch for CVE-2026-39855, CVE-2026-39853, CVE-2025-70888, CVE-2026-39855 * Tue Feb 13 2024 Cameron Baird 2.7-1 - Original version for CBL-Mariner (license: MIT).