[PATCH] libselinux: fix SEGV in JIT matching of recursive patterns in partial mode

Petr Matyas <[email protected]>
Newsgroups org.kernel.vger.selinux
Message-ID <[email protected]>
The PCRE2 JIT compiler has a bug in its PCRE2_JIT_PARTIAL_SOFT code
path: patterns containing recursive subroutine calls (the (?1...)
syntax) cause the generated native code to dereference a null pointer
at match time. pcre2_jit_compile() returns 0 (success) and the
compiled JIT size is non-zero, so the bug is undetectable at compile
time and only manifests when pcre2_match() executes the JIT code.

The root cause is an interaction between OP_RECURSE backtracking and
the hit_start tracking mechanism that the partial-soft JIT uses to
remember the earliest position at which a partial match was seen.
No fix is currently available in PCRE2.

Commit 92af7f1b61db ("libselinux: prevent ReDoS in file context regex
matching") introduced pcre2_jit_compile() calls with both
PCRE2_JIT_COMPLETE and PCRE2_JIT_PARTIAL_SOFT. ClusterFuzz
subsequently reported a SEGV in selabel_file_compiled-fuzzer via a
crafted compiled file_contexts input that triggers the bug through
the lazy text-compilation fallback path (version/arch mismatch causes
the pre-compiled PCRE2 data to be skipped, so the embedded regex
string is compiled on demand via regex_prepare_data()).

Fix by dropping PCRE2_JIT_PARTIAL_SOFT. Per the PCRE2 documentation,
when partial-soft JIT code has not been compiled, pcre2_match()
automatically falls back to the interpreter for partial matches.
Partial matches remain protected against ReDoS by the 10 000 000-step
backtrack limit that was introduced in the same commit. Full matches
continue to use PCRE2_JIT_COMPLETE and are unaffected.

Reported-by: ClusterFuzz (testcase 5660382656790528)
Fixes: 92af7f1b61db ("libselinux: prevent ReDoS in file context regex matching")
Signed-off-by: Petr Matyas <[email protected]>
---
 libselinux/src/regex.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/libselinux/src/regex.c b/libselinux/src/regex.c
index 3f7df4c7..017647b4 100644
--- a/libselinux/src/regex.c
+++ b/libselinux/src/regex.c
@@ -103,11 +103,12 @@ int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
 		goto err;
 	}
 
-	/* JIT-compile for complete and partial matching. pcre2_match() uses the
-	 * JIT automatically when available, avoiding the interpreter's
-	 * susceptibility to catastrophic backtracking. Failures are non-fatal. */
-	(void)pcre2_jit_compile((*regex)->regex,
-				PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT);
+	/* JIT-compile for complete matching only. pcre2_match() uses the JIT
+	 * automatically when available, avoiding the interpreter's
+	 * susceptibility to catastrophic backtracking. Partial matches fall
+	 * back to the interpreter, protected by the match limit. Failures
+	 * are non-fatal. */
+	(void)pcre2_jit_compile((*regex)->regex, PCRE2_JIT_COMPLETE);
 
 	return 0;
 
@@ -163,9 +164,7 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
 		if (rc != 1)
 			goto err;
 
-		(void)pcre2_jit_compile((*regex)->regex,
-					PCRE2_JIT_COMPLETE |
-						PCRE2_JIT_PARTIAL_SOFT);
+		(void)pcre2_jit_compile((*regex)->regex, PCRE2_JIT_COMPLETE);
 
 		*regex_compiled = true;
 	}
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.