Re: [PATCH] mcstrans: escape config text spliced into build_regexps() patterns
James Carter <[email protected]>
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <CAP+JOzQnq8khhFY43BSytNv-Z8JSimhAYrCzz6xQqBpVyGXG2A@mail.gmail.com> |
On Thu, Aug 13, 2026 at 2:41 PM Stephen Smalley <[email protected]> wrote: > > build_regexps() interpolates the base-classification, prefix/suffix > affix, word and Whitespace strings from the setrans configuration > directly into PCRE alternation patterns. A label containing a PCRE > metacharacter such as "." or "(" therefore either fails to compile, > matches unintended input, or produces a pathological regex that a > client can drive via TRANS_TO_RAW_CONTEXT. The Whitespace value goes > into a character class, where an unescaped "-" between two characters > is treated as a range and "]" ends the class early. > > Backslash-escape the fixed PCRE metacharacter set when appending > config-supplied text; the same escaping is safe both inside and > outside a character class. None of the shipped example configurations > carry metacharacters in these fields, so behaviour is unchanged for > them. The configuration is root-owned, so this is hardening rather > than a boundary crossing. > > Signed-off-by: Stephen Smalley <[email protected]> Acked-by: James Carter <[email protected]> > --- > mcstrans/src/mcstrans.c | 42 ++++++++++++++++++++++++++++++++++++----- > 1 file changed, 37 insertions(+), 5 deletions(-) > > diff --git a/mcstrans/src/mcstrans.c b/mcstrans/src/mcstrans.c > index 89235269..9704f5dc 100644 > --- a/mcstrans/src/mcstrans.c > +++ b/mcstrans/src/mcstrans.c > @@ -1074,6 +1074,32 @@ static int buf_append(char **buf, size_t *cap, size_t *len, const char *s) > return 0; > } > > +/* > + * Append s with PCRE metacharacters backslash-escaped so it matches > + * literally. Used for config-supplied label/word/affix/whitespace > + * text spliced into the alternation patterns in build_regexps(). > + * Works both inside and outside a character class. > + */ > +static int buf_append_literal(char **buf, size_t *cap, size_t *len, > + const char *s) > +{ > + char esc[3] = { '\\', 0, 0 }; > + char lit[2] = { 0, 0 }; > + > + for (; *s; s++) { > + if (strchr("\\^$.|?*+()[]{}-", *s)) { > + esc[1] = *s; > + if (buf_append(buf, cap, len, esc)) > + return -1; > + } else { > + lit[0] = *s; > + if (buf_append(buf, cap, len, lit)) > + return -1; > + } > + } > + return 0; > +} > + > static void build_regexp(pcre2_code **r, char *buffer) > { > int error; > @@ -1106,6 +1132,11 @@ static int build_regexps(domain_t *domain) > if (buf_append(&buffer, &cap, &len, (s))) \ > goto err; \ > } while (0) > +#define APPEND_LIT(s) \ > + do { \ > + if (buf_append_literal(&buffer, &cap, &len, (s))) \ > + goto err; \ > + } while (0) > #define RESET() \ > do { \ > len = 0; \ > @@ -1133,7 +1164,7 @@ static int build_regexps(domain_t *domain) > qsort(sortable, n_el, sizeof(char *), string_size); > > for (i = 0; i < n_el; i++) { > - APPEND(sortable[i]); > + APPEND_LIT(sortable[i]); > if (i != (n_el - 1)) > APPEND("|"); > } > @@ -1149,7 +1180,7 @@ static int build_regexps(domain_t *domain) > if (g->prefixes) { > APPEND("(?:"); > for (a = g->prefixes; a; a = a->next) { > - APPEND(a->text); > + APPEND_LIT(a->text); > if (a->next) > APPEND("|"); > } > @@ -1185,13 +1216,13 @@ static int build_regexps(domain_t *domain) > if (i) > APPEND("|"); > APPEND("\\b"); > - APPEND(g->sword[i]->text); > + APPEND_LIT(g->sword[i]->text); > APPEND("\\b"); > } > > if (g->whitespace) { > APPEND("|["); > - APPEND(g->whitespace); > + APPEND_LIT(g->whitespace); > APPEND("]+"); > } > > @@ -1208,7 +1239,7 @@ static int build_regexps(domain_t *domain) > APPEND("[ ]+"); > APPEND("(?:"); > for (a = g->suffixes; a; a = a->next) { > - APPEND(a->text); > + APPEND_LIT(a->text); > if (a->next) > APPEND("|"); > } > @@ -1227,6 +1258,7 @@ err: > free(buffer); > return -1; > #undef APPEND > +#undef APPEND_LIT > #undef RESET > } > > -- > 2.55.0 >