[PATCH] mcstrans: escape config text spliced into build_regexps() patterns
Stephen Smalley <[email protected]>
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <[email protected]> |
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]>
---
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