Skip to content

Commit 3a70d6e

Browse files
committed
Merge branch 'cb/grep-fallback-failing-jit' into next
In an environment where dynamically generated code is prohibited to run (e.g. SELinux), failure to JIT pcre patterns is expected. Fall back to interpreted execution in such a case. * cb/grep-fallback-failing-jit: grep: fall back to interpreter if JIT memory allocation fails
2 parents bfd4509 + 50b6ad5 commit 3a70d6e

File tree

1 file changed

+48
-2
lines changed

1 file changed

+48
-2
lines changed

grep.c

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,31 @@ static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
262262
free(pointer);
263263
}
264264

265+
static int pcre2_jit_functional(void)
266+
{
267+
static int jit_working = -1;
268+
pcre2_code *code;
269+
size_t off;
270+
int err;
271+
272+
if (jit_working != -1)
273+
return jit_working;
274+
275+
/*
276+
* Try to JIT compile a simple pattern to probe if the JIT is
277+
* working in general. It might fail for systems where creating
278+
* memory mappings for runtime code generation is restricted.
279+
*/
280+
code = pcre2_compile((PCRE2_SPTR)".", 1, 0, &err, &off, NULL);
281+
if (!code)
282+
return 0;
283+
284+
jit_working = pcre2_jit_compile(code, PCRE2_JIT_COMPLETE) == 0;
285+
pcre2_code_free(code);
286+
287+
return jit_working;
288+
}
289+
265290
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
266291
{
267292
int error;
@@ -317,8 +342,29 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
317342
pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
318343
if (p->pcre2_jit_on) {
319344
jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE);
320-
if (jitret)
321-
die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret);
345+
if (jitret == PCRE2_ERROR_NOMEMORY && !pcre2_jit_functional()) {
346+
/*
347+
* Even though pcre2_config(PCRE2_CONFIG_JIT, ...)
348+
* indicated JIT support, the library might still
349+
* fail to generate JIT code for various reasons,
350+
* e.g. when SELinux's 'deny_execmem' or PaX's
351+
* MPROTECT prevent creating W|X memory mappings.
352+
*
353+
* Instead of faling hard, fall back to interpreter
354+
* mode, just as if the pattern was prefixed with
355+
* '(*NO_JIT)'.
356+
*/
357+
p->pcre2_jit_on = 0;
358+
return;
359+
} else if (jitret) {
360+
int need_clip = p->patternlen > 64;
361+
int clip_len = need_clip ? 64 : p->patternlen;
362+
die("Couldn't JIT the PCRE2 pattern '%.*s'%s, got '%d'%s",
363+
clip_len, p->pattern, need_clip ? "..." : "", jitret,
364+
pcre2_jit_functional()
365+
? "\nPerhaps prefix (*NO_JIT) to your pattern?"
366+
: "");
367+
}
322368

323369
/*
324370
* The pcre2_config(PCRE2_CONFIG_JIT, ...) call just

0 commit comments

Comments
 (0)