From 30a7f9efc7f1563a355579fcd23589e851dee5de Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy Date: Tue, 27 Oct 2026 11:41:08 +0000 Subject: [PATCH] regex: fix BRE backref OOB read on multibyte input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the input position is tracked by pos and str_byte such that string+pos+pos_add_next == str_byte the current char (next_c) is decoded from [string+pos, str_byte). however pos_add_next was not always updated, which usually meant incorrect matches on multibyte input. \(a\)\1\(b\|.\)* vs aabáá was (0,8)(0,1)(6,8) now (0,7)(0,1)(5,7) and in some cases it could lead to oob read access. setlocale(0,""); regcomp(&re,"\\(a\\|b\\|..*\\)_\\1\\(.\\)\\2",0); regexec(&re,"ab_\xf1\x81\x81\x81_\xf1\x81\x81\x81__",3,rm,0); was oob read (crash or nomatch), now (3,14)(3,7)(12,13). the first char of a backref match was assumed to be a single byte which could also break positions. with an utf8 locale \(.*\)_\1 vs á_á was nomatch, now (0,5)(0,2) the fix computes pos_add_next based on the invariant above whenever pos and str_byte are modified. and uses it in backref handling. --- src/regex/regexec.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/regex/regexec.c b/src/regex/regexec.c index 253b0e14..683c9e45 100644 --- a/src/regex/regexec.c +++ b/src/regex/regexec.c @@ -577,6 +577,7 @@ typedef struct tre_backtrack_struct { assert(stack->prev); \ pos = stack->item.pos; \ str_byte = stack->item.str_byte; \ + pos_add_next = str_byte - (const char*)string - pos; \ state = stack->item.state; \ next_c = stack->item.next_c; \ for (i = 0; i < tnfa->num_tags; i++) \ @@ -692,6 +693,7 @@ tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string, state = NULL; pos = pos_start; + pos_add_next = str_byte - (const char*)string - pos; GET_NEXT_WCHAR(); pos_start = pos; next_c_start = next_c; @@ -782,7 +784,7 @@ tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string, eo = pmatch[bt].rm_eo; bt_len = eo - so; - result = strncmp((const char*)string + so, str_byte - 1, + result = strncmp((const char*)string + so, str_byte - pos_add_next, (size_t)bt_len); if (result == 0) @@ -799,8 +801,8 @@ tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string, /* Advance in input string and resync `prev_c', `next_c' and pos. */ - str_byte += bt_len - 1; - pos += bt_len - 1; + str_byte += bt_len - pos_add_next; + pos += bt_len - pos_add_next; GET_NEXT_WCHAR(); } else -- 2.52.0