diff mbox series

[wrynose,7/8] libpcre2: patch CVE-2026-86145

Message ID 20261009184548.2962197-7-peter.marko@siemens.com
State New
Headers show
Series [wrynose,1/8] libpcre2: patch CVE-2026-89162 | expand

Commit Message

Peter Marko Oct. 9, 2026, 6:45 p.m. UTC
From: Peter Marko <peter.marko@siemens.com>

Pick patch per [1] since [2] does not provide valid commit hash.

[1] https://security-tracker.debian.org/tracker/CVE-2026-86145
[2] https://github.com/PCRE2Project/pcre2/security/advisories/GHSA-3r4p-g7gg-ppmf

Signed-off-by: Peter Marko <peter.marko@siemens.com>
---
 .../libpcre/libpcre2/CVE-2026-86145.patch     | 158 ++++++++++++++++++
 .../recipes-support/libpcre/libpcre2_10.47.bb |   1 +
 2 files changed, 159 insertions(+)
 create mode 100644 meta/recipes-support/libpcre/libpcre2/CVE-2026-86145.patch
diff mbox series

Patch

diff --git a/meta/recipes-support/libpcre/libpcre2/CVE-2026-86145.patch b/meta/recipes-support/libpcre/libpcre2/CVE-2026-86145.patch
new file mode 100644
index 0000000000..a044a006e5
--- /dev/null
+++ b/meta/recipes-support/libpcre/libpcre2/CVE-2026-86145.patch
@@ -0,0 +1,158 @@ 
+From c932e70451eafef922ebef364ac25042f0031135 Mon Sep 17 00:00:00 2001
+From: Nicholas Wilson <nicholas@nicholaswilson.me.uk>
+Date: Thu, 27 Aug 2026 16:52:16 +0100
+Subject: [PATCH] Fix DFA workspace overflows; see GHSA-3r4p-g7gg-ppmf for
+ details
+
+CVE: CVE-2026-86145
+Upstream-Status: Backport [https://github.com/PCRE2Project/pcre2/commit/c932e70451eafef922ebef364ac25042f0031135]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ src/pcre2_dfa_match.c | 44 ++++++++++++++++++++++++++++++++++++-------
+ testdata/testinput6   |  7 +++++++
+ testdata/testoutput6  |  8 ++++++++
+ 3 files changed, 52 insertions(+), 7 deletions(-)
+
+diff --git a/src/pcre2_dfa_match.c b/src/pcre2_dfa_match.c
+index 314e9775..8e9512c4 100644
+--- a/src/pcre2_dfa_match.c
++++ b/src/pcre2_dfa_match.c
+@@ -405,8 +405,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)
+@@ -422,9 +422,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;
+   }
+ 
+@@ -434,14 +443,30 @@ overflow. */
+ 
+ else
+   {
+-  uint32_t newsize = (rws->size >= UINT32_MAX/(sizeof(int)*2))? UINT32_MAX/sizeof(int) : 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 (newsize < RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE)
++  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 < requested)
+     return PCRE2_ERROR_HEAPLIMIT;
+   new = mb->memctl.malloc(newsize*sizeof(int), mb->memctl.memory_data);
+   if (new == NULL) return PCRE2_ERROR_NOMEMORY;
+@@ -2801,6 +2826,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);
+@@ -2900,6 +2926,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);
+@@ -2951,6 +2978,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
+@@ -3050,6 +3078,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)
+@@ -3149,6 +3178,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 f6f5cbf4..197f6f76 100644
+--- a/testdata/testinput6
++++ b/testdata/testinput6
+@@ -5263,4 +5263,11 @@
+     abc\=replace=xyz
+     abc\=replace=xyz,substitute_matched
+ 
++# --------------
++
++# Test workspace resizing and workspace re-use
++
++/(*LIMIT_HEAP=4)(?=(?=(?=(?=(?=(?=(?=(?=a))(?R)))))))./
++    a\=dfa
++
+ # End of testinput6
+diff --git a/testdata/testoutput6 b/testdata/testoutput6
+index 8ecf0040..4316c8a6 100644
+--- a/testdata/testoutput6
++++ b/testdata/testoutput6
+@@ -8237,4 +8237,12 @@ Failed: error -42: pattern contains an item that is not supported for DFA matchi
+     abc\=replace=xyz,substitute_matched
+ Failed: error -41: function is not supported for DFA matching
+ 
++# --------------
++
++# Test workspace resizing and workspace re-use
++
++/(*LIMIT_HEAP=4)(?=(?=(?=(?=(?=(?=(?=(?=a))(?R)))))))./
++    a\=dfa
++Failed: error -63: heap limit exceeded
++
+ # End of testinput6
diff --git a/meta/recipes-support/libpcre/libpcre2_10.47.bb b/meta/recipes-support/libpcre/libpcre2_10.47.bb
index 2f40ef463e..60ba56014b 100644
--- a/meta/recipes-support/libpcre/libpcre2_10.47.bb
+++ b/meta/recipes-support/libpcre/libpcre2_10.47.bb
@@ -20,6 +20,7 @@  SRC_URI = "${GITHUB_BASE_URI}/download/pcre2-${PV}/pcre2-${PV}.tar.bz2 \
            file://CVE-2026-89157.patch \
            file://CVE-2026-89160.patch \
            file://CVE-2026-89158.patch \
+           file://CVE-2026-86145.patch \
 "
 
 GITHUB_BASE_URI = "https://github.com/PCRE2Project/pcre2/releases"