GiB, TiB, PiB, EiB, ZiB, and YiB (the "iB" is optional, e.g., "K" has the same
meaning as "KiB").
+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
+memory consumption in the POSIX regex compiler.
+
== AUTHORS
mailto:kzak@redhat.com[Karel Zak]
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. */
+static int is_unsafe_regex(const char *pattern)
+{
+ size_t i, len = strlen(pattern);
+
+ for (i = 0; i + 1 < len; i++) {
+ if ((pattern[i] == '+' || pattern[i] == '*')
+ && (pattern[i + 1] == '+' || pattern[i + 1] == '*'))
+ return 1;
+
+ if (pattern[i] == ')'
+ && (pattern[i + 1] == '+' || pattern[i + 1] == '*')) {
+ int j;
+
+ for (j = (int) i - 1; j >= 0; j--) {
+ if (pattern[j] == '(')
+ break;
+ if (pattern[j] == '+' || pattern[j] == '*')
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
int filter_compile_param(struct libscols_filter *fltr, struct filter_param *n)
{
int rc;
return 0;
if (n->type != SCOLS_DATA_STRING || !n->val.str)
return -EINVAL;
+ if (strlen(n->val.str) > SCOLS_FILTER_MAX_REGSZ)
+ return -EINVAL;
+ if (is_unsafe_regex(n->val.str))
+ return -EINVAL;
n->re = calloc(1, sizeof(regex_t));
if (!n->re)
static void process_string(const char *str)
{
- /* Parse the input as a libsmartcols filter expression. This drives the
- flex scanner, the bison grammar, parameter/holder construction and the
- regcomp() done for the =~ operator. */
- struct libscols_filter *fltr = scols_new_filter(str);
+ struct libscols_filter *fltr = scols_new_filter(str);
- scols_unref_filter(fltr);
+ scols_unref_filter(fltr);
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
- char *str;
+ char *str;
- /* Larger than the library's 1024-byte limit to exercise the
- * rejection path, small enough to avoid OOM in sanitizer builds */
- if (size > 4096)
- return 0;
+ if (size > 4096)
+ return 0;
- str = malloc(size + 1);
- if (!str)
- return 0;
+ str = malloc(size + 1);
+ if (!str)
+ return 0;
- memcpy(str, data, size);
- str[size] = '\0';
+ memcpy(str, data, size);
+ str[size] = '\0';
- process_string(str);
+ process_string(str);
- free(str);
- return 0;
+ free(str);
+ return 0;
}
#ifndef FUZZ_TARGET
int main(int argc, char **argv)
{
- for (int i = 1; i < argc; i++) {
- FILE *f = fopen(argv[i], "r");
- char *buf;
- long len;
- size_t n;
+ for (int i = 1; i < argc; i++) {
+ FILE *f = fopen(argv[i], "r");
+ char *buf;
+ long len;
+ size_t n;
- if (!f)
- continue;
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
- if (len < 0) {
- fclose(f);
- continue;
- }
- buf = malloc(len + 1);
- if (!buf) {
- fclose(f);
- continue;
- }
- n = fread(buf, 1, len, f);
- fclose(f);
- buf[n] = '\0';
- process_string(buf);
- free(buf);
- }
- return 0;
+ if (!f)
+ continue;
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ if (len < 0) {
+ fclose(f);
+ continue;
+ }
+ buf = malloc(len + 1);
+ if (!buf) {
+ fclose(f);
+ continue;
+ }
+ n = fread(buf, 1, len, f);
+ fclose(f);
+ buf[n] = '\0';
+ process_string(buf);
+ free(buf);
+ }
+ return 0;
}
#endif
#define SCOLS_FILTER_MAX_EXPRSZ 1024
#define SCOLS_FILTER_MAX_NODES 256
+#define SCOLS_FILTER_MAX_REGSZ 256
struct filter_node *__filter_new_node(enum filter_ntype type, size_t sz);
void filter_ref_node(struct filter_node *n);