Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions SPECS/pcre2/CVE-2026-86145.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
From d2fac7caedfd08b5070706a5ddaca66fcd4fd164 Mon Sep 17 00:00:00 2001
From: AllSpark <allspark@microsoft.com>
Date: Mon, 7 Sep 2026 06:27:43 +0000
Subject: [PATCH] Fix DFA workspace overflows; see GHSA-3r4p-g7gg-ppmf for
details

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: AI Backport of https://github.com/PCRE2Project/pcre2/commit/c932e70451eafef922ebef364ac25042f0031135.patch
---
src/pcre2_dfa_match.c | 43 ++++++++++++++++++++++++++++++++++++-------
testdata/testinput6 | 7 +++++++
testdata/testoutput6 | 8 ++++++++
3 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/src/pcre2_dfa_match.c b/src/pcre2_dfa_match.c
index b16e594..6f0defe 100644
--- a/src/pcre2_dfa_match.c
+++ b/src/pcre2_dfa_match.c
@@ -397,8 +397,8 @@ return (mb->callout)(cb, mb->callout_data);

/* This function is called when internal_dfa_match() is about to be called
recursively and there is insufficient working space left in the current
-workspace block. If there's an existing next block, use it; otherwise get a new
-block unless the heap limit is reached.
+workspace block. If there's a sufficiently large next block, use it; get a new
+block unless the heap limit is (or has been) reached.

Arguments:
rwsptr pointer to block pointer (updated)
@@ -414,9 +414,18 @@ more_workspace(RWS_anchor **rwsptr, unsigned int ovecsize, dfa_match_block *mb)
{
RWS_anchor *rws = *rwsptr;
RWS_anchor *new;
+uint32_t requested;
+
+PCRE2_ASSERT(ovecsize <= UINT32_MAX - RWS_RSIZE - RWS_ANCHOR_SIZE);
+requested = RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE;

if (rws->next != NULL)
{
+ /* Although the initial block is large, and subsequent ones try to double, the
+ heap limit may cause the last one to be smaller; in this case, we have already
+ hit the heap limit and allocating a larger block will not be possible. */
+ if (rws->next->size < requested)
+ return PCRE2_ERROR_HEAPLIMIT;
new = rws->next;
}

@@ -426,14 +435,30 @@ overflow. */

else
{
- uint32_t newsize = (rws->size >= UINT32_MAX/2)? UINT32_MAX/2 : rws->size * 2;
+ uint32_t newsize = (rws->size >= (UINT32_MAX/sizeof(int))/2)?
+ UINT32_MAX/sizeof(int) : rws->size * 2;
uint32_t newsizeK = newsize/(1024/sizeof(int));

- if (newsizeK + mb->heap_used > mb->heap_limit)
- newsizeK = (uint32_t)(mb->heap_limit - mb->heap_used);
- newsize = newsizeK*(1024/sizeof(int));
+ /* Clamp the allocation to the remaining heap allowance with care for overflows */
+
+ if (mb->heap_used >= mb->heap_limit)
+ {
+ newsize = 0;
+ newsizeK = 0;
+ }
+ else
+ {
+ PCRE2_SIZE availableK = mb->heap_limit - mb->heap_used;
+ /* newsize always capped at UINT32_MAX/sizeof(int), so newsizeK also capped;
+ and - if availableK is smaller - then multiplication to form newsize is safe */
+ if (newsizeK > availableK)
+ {
+ newsize = (uint32_t)(availableK*(1024/sizeof(int)));
+ newsizeK = availableK;
+ }
+ }

- if (newsize < RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE)
+ if (newsize < requested)
return PCRE2_ERROR_HEAPLIMIT;
new = mb->memctl.malloc(newsize*sizeof(int), mb->memctl.memory_data);
if (new == NULL) return PCRE2_ERROR_NOMEMORY;
@@ -2760,6 +2785,7 @@ for (;;)

local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;

while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
@@ -2908,6 +2934,7 @@ for (;;)

local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
local_workspace = ((int *)local_offsets) + RWS_OVEC_RSIZE;
+ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_RSIZE);
rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE;

/* Check for repeating a recursion without advancing the subject
@@ -3001,6 +3028,7 @@ for (;;)

local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;

if (codevalue == OP_BRAPOSZERO)
@@ -3100,6 +3128,7 @@ for (;;)

local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE);
rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;

rc = internal_dfa_match(
diff --git a/testdata/testinput6 b/testdata/testinput6
index 0ca0d23..376840f 100644
--- a/testdata/testinput6
+++ b/testdata/testinput6
@@ -5027,3 +5027,10 @@
ab\=ph,offset=2

# End of testinput6
+
+# --------------
+
+# Test workspace resizing and workspace re-use
+
+/(*LIMIT_HEAP=4)(?=(?=(?=(?=(?=(?=(?=(?=a))(?R)))))))./
+ a\=dfa
diff --git a/testdata/testoutput6 b/testdata/testoutput6
index 607b572..cac6343 100644
--- a/testdata/testoutput6
+++ b/testdata/testoutput6
@@ -7896,3 +7896,11 @@ Partial match:
Partial match:

# End of testinput6
+
+# --------------
+
+# Test workspace resizing and workspace re-use
+
+/(*LIMIT_HEAP=4)(?=(?=(?=(?=(?=(?=(?=(?=a))(?R)))))))./
+ a\=dfa
+Failed: error -63: heap limit exceeded
--
2.45.4

7 changes: 6 additions & 1 deletion SPECS/pcre2/pcre2.spec
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
Summary: A library for Perl-compatible regular expressions
Name: pcre2
Version: 10.42
Release: 3%{?dist}
Release: 4%{?dist}
License: BSD
Vendor: Microsoft Corporation
Distribution: Azure Linux
Group: Development/Libraries/C and C++
URL: https://www.pcre.org/
Source0: https://github.com/PhilipHazel/%{name}/releases/download/%{name}-%{version}/%{name}-%{version}.tar.bz2
Patch0: CVE-2026-86145.patch
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: bzip2-devel
Expand Down Expand Up @@ -148,6 +149,7 @@ API.

%prep
%setup -q
%patch 0 -p1

%build
# Available JIT archs see sljit/sljitConfig.h
Expand Down Expand Up @@ -235,6 +237,9 @@ make check -j1
%{_libdir}/*.a

%changelog
* Mon Sep 07 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 10.42-4
- Patch for CVE-2026-86145

* Mon Mar 25 2024 Chris PeBenito <chpebeni@microsoft.com> 10.42-3
- Drop coreutils BuildRequires to break dependency cycle between pcre2, libselinux, and coreutils.

Expand Down
20 changes: 10 additions & 10 deletions toolkit/resources/manifests/package/toolchain_aarch64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,10 @@ libmetalink-debuginfo-0.1.3-1.azl3.aarch64.rpm
libmetalink-devel-0.1.3-1.azl3.aarch64.rpm
libmpc-1.3.1-1.azl3.aarch64.rpm
libmpc-debuginfo-1.3.1-1.azl3.aarch64.rpm
libpcre2-16-0-10.42-3.azl3.aarch64.rpm
libpcre2-32-0-10.42-3.azl3.aarch64.rpm
libpcre2-8-0-10.42-3.azl3.aarch64.rpm
libpcre2-posix2-10.42-3.azl3.aarch64.rpm
libpcre2-16-0-10.42-4.azl3.aarch64.rpm
libpcre2-32-0-10.42-4.azl3.aarch64.rpm
libpcre2-8-0-10.42-4.azl3.aarch64.rpm
libpcre2-posix2-10.42-4.azl3.aarch64.rpm
libpipeline-1.5.7-1.azl3.aarch64.rpm
libpipeline-debuginfo-1.5.7-1.azl3.aarch64.rpm
libpipeline-devel-1.5.7-1.azl3.aarch64.rpm
Expand Down Expand Up @@ -304,12 +304,12 @@ pam-devel-1.5.3-5.azl3.aarch64.rpm
pam-lang-1.5.3-5.azl3.aarch64.rpm
patch-2.7.6-10.azl3.aarch64.rpm
patch-debuginfo-2.7.6-10.azl3.aarch64.rpm
pcre2-10.42-3.azl3.aarch64.rpm
pcre2-debuginfo-10.42-3.azl3.aarch64.rpm
pcre2-devel-10.42-3.azl3.aarch64.rpm
pcre2-devel-static-10.42-3.azl3.aarch64.rpm
pcre2-doc-10.42-3.azl3.noarch.rpm
pcre2-tools-10.42-3.azl3.aarch64.rpm
pcre2-10.42-4.azl3.aarch64.rpm
pcre2-debuginfo-10.42-4.azl3.aarch64.rpm
pcre2-devel-10.42-4.azl3.aarch64.rpm
pcre2-devel-static-10.42-4.azl3.aarch64.rpm
pcre2-doc-10.42-4.azl3.noarch.rpm
pcre2-tools-10.42-4.azl3.aarch64.rpm
perl-5.38.2-514.azl3.aarch64.rpm
perl-Archive-Tar-2.40-514.azl3.noarch.rpm
perl-Attribute-Handlers-1.03-514.azl3.noarch.rpm
Expand Down
20 changes: 10 additions & 10 deletions toolkit/resources/manifests/package/toolchain_x86_64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,10 @@ libmetalink-debuginfo-0.1.3-1.azl3.x86_64.rpm
libmetalink-devel-0.1.3-1.azl3.x86_64.rpm
libmpc-1.3.1-1.azl3.x86_64.rpm
libmpc-debuginfo-1.3.1-1.azl3.x86_64.rpm
libpcre2-16-0-10.42-3.azl3.x86_64.rpm
libpcre2-32-0-10.42-3.azl3.x86_64.rpm
libpcre2-8-0-10.42-3.azl3.x86_64.rpm
libpcre2-posix2-10.42-3.azl3.x86_64.rpm
libpcre2-16-0-10.42-4.azl3.x86_64.rpm
libpcre2-32-0-10.42-4.azl3.x86_64.rpm
libpcre2-8-0-10.42-4.azl3.x86_64.rpm
libpcre2-posix2-10.42-4.azl3.x86_64.rpm
libpipeline-1.5.7-1.azl3.x86_64.rpm
libpipeline-debuginfo-1.5.7-1.azl3.x86_64.rpm
libpipeline-devel-1.5.7-1.azl3.x86_64.rpm
Expand Down Expand Up @@ -312,12 +312,12 @@ pam-devel-1.5.3-5.azl3.x86_64.rpm
pam-lang-1.5.3-5.azl3.x86_64.rpm
patch-2.7.6-10.azl3.x86_64.rpm
patch-debuginfo-2.7.6-10.azl3.x86_64.rpm
pcre2-10.42-3.azl3.x86_64.rpm
pcre2-debuginfo-10.42-3.azl3.x86_64.rpm
pcre2-devel-10.42-3.azl3.x86_64.rpm
pcre2-devel-static-10.42-3.azl3.x86_64.rpm
pcre2-doc-10.42-3.azl3.noarch.rpm
pcre2-tools-10.42-3.azl3.x86_64.rpm
pcre2-10.42-4.azl3.x86_64.rpm
pcre2-debuginfo-10.42-4.azl3.x86_64.rpm
pcre2-devel-10.42-4.azl3.x86_64.rpm
pcre2-devel-static-10.42-4.azl3.x86_64.rpm
pcre2-doc-10.42-4.azl3.noarch.rpm
pcre2-tools-10.42-4.azl3.x86_64.rpm
perl-5.38.2-514.azl3.x86_64.rpm
perl-Archive-Tar-2.40-514.azl3.noarch.rpm
perl-Attribute-Handlers-1.03-514.azl3.noarch.rpm
Expand Down
Loading