From: Karel Zak Date: Tue, 30 Jun 2026 10:49:26 +0000 (+0200) Subject: libsmartcols: reject large interval repetition bounds in filter regex X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f9baae05e3b467da0c4e72254dd7018151639a8f;p=thirdparty%2Futil-linux.git libsmartcols: reject large interval repetition bounds in filter regex ERE interval expressions like {,32232} cause glibc regcomp() to allocate gigabytes for the NFA, triggering OOM even on tiny inputs. The existing consecutive-quantifier and nested-group checks do not catch this pattern. Scan numbers inside {...} and reject any bound exceeding SCOLS_FILTER_MAX_REPCNT (1024). Document the new limit in scols-filter(5). Addresses: https://oss-fuzz.com/testcase-detail/6017673394454528 Signed-off-by: Karel Zak --- diff --git a/libsmartcols/scols-filter.5.adoc b/libsmartcols/scols-filter.5.adoc index 5822ac00a..315218ede 100644 --- a/libsmartcols/scols-filter.5.adoc +++ b/libsmartcols/scols-filter.5.adoc @@ -115,8 +115,9 @@ The filter expression string is limited to 1024 bytes. The number of nodes (parameters and operators) in a single expression is limited to 256. Regular expression patterns used with the `=~` and `!~` operators are limited to -256 bytes. Patterns with consecutive quantifiers (e.g., `a++`, `a**`) or nested -group repetitions (e.g., `(a+)+`) are rejected because they can cause excessive +256 bytes. Patterns with consecutive quantifiers (e.g., `a++`, `a**`), nested +group repetitions (e.g., `(a+)+`), or interval repetitions with bounds larger +than 1024 (e.g., `{,9999}`) are rejected because they can cause excessive memory consumption in the POSIX regex compiler. == AUTHORS diff --git a/libsmartcols/src/filter-param.c b/libsmartcols/src/filter-param.c index b7bff6968..c77ae397c 100644 --- a/libsmartcols/src/filter-param.c +++ b/libsmartcols/src/filter-param.c @@ -131,8 +131,9 @@ struct filter_node *filter_new_param( return (struct filter_node *) n; } -/* Consecutive ERE quantifiers (a++, a**) and nested group repetitions - * ((a+)+, (a*)*) cause glibc regcomp() to allocate gigabytes for the NFA. */ +/* Consecutive ERE quantifiers (a++, a**), nested group repetitions + * ((a+)+, (a*)*), and large interval bounds ({,N} where N is huge) + * cause glibc regcomp() to allocate gigabytes for the NFA. */ static int is_unsafe_regex(const char *pattern) { size_t i, len = strlen(pattern); @@ -153,6 +154,25 @@ static int is_unsafe_regex(const char *pattern) return 1; } } + + /* reject large ERE interval bounds like {,32232} or {1,9999} */ + if (pattern[i] == '{') { + const char *p = &pattern[i + 1]; + + while (*p && *p != '}') { + if (*p >= '0' && *p <= '9') { + unsigned long val; + char *end = NULL; + + errno = 0; + val = strtoul(p, &end, 10); + if (errno || val > SCOLS_FILTER_MAX_REPCNT) + return 1; + p = end; + } else + p++; + } + } } return 0; } diff --git a/libsmartcols/src/smartcolsP.h b/libsmartcols/src/smartcolsP.h index f7504830d..b252ee02c 100644 --- a/libsmartcols/src/smartcolsP.h +++ b/libsmartcols/src/smartcolsP.h @@ -567,6 +567,7 @@ struct libscols_filter { #define SCOLS_FILTER_MAX_EXPRSZ 1024 #define SCOLS_FILTER_MAX_NODES 256 #define SCOLS_FILTER_MAX_REGSZ 256 +#define SCOLS_FILTER_MAX_REPCNT 1024 struct filter_node *__filter_new_node(enum filter_ntype type, size_t sz); void filter_ref_node(struct filter_node *n);