diff --git a/src/c2.c b/src/c2.c index 6f864c9b..4112d7e6 100644 --- a/src/c2.c +++ b/src/c2.c @@ -486,6 +486,18 @@ TEST_CASE(c2_parse) { cond = c2_parse(NULL, "_NET_WM_STATE = '_NET_WM_STATE_HIDDEN'", NULL); TEST_EQUAL(cond, NULL); + + cond = c2_parse(NULL, "1A:\n1111111111111ar1", NULL); + TEST_EQUAL(cond, NULL); + + cond = c2_parse(NULL, "N [4444444444444: \n", NULL); + TEST_EQUAL(cond, NULL); + + cond = c2_parse(NULL, " x:a=\"b\377\\xCCCCC", NULL); + TEST_EQUAL(cond, NULL); + + cond = c2_parse(NULL, "!!!!!!!((((((!(((((,", NULL); + TEST_EQUAL(cond, NULL); } #define c2_error(format, ...) \ @@ -507,11 +519,6 @@ TEST_CASE(c2_parse) { * @return offset of next character in string */ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int level) { - // Check for recursion levels - if (level > C2_MAX_LEVELS) { - c2_error("Exceeded maximum recursion levels."); - } - if (!pattern) { return -1; } @@ -538,6 +545,11 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int // after encountering a logical operator bool next_expected = true; + // Check for recursion levels + if (level > C2_MAX_LEVELS) { + c2_error("Exceeded maximum recursion levels."); + } + // Parse the pattern character-by-character for (; pattern[offset]; ++offset) { assert(elei <= 2); @@ -761,8 +773,11 @@ static int c2_parse_target(const char *pattern, int offset, c2_ptr_t *presult) { if (!endptr || pattern + offset == endptr) { c2_error("No index number found after bracket."); } + if (index > INT_MAX) { + c2_error("Index %ld too large.", index); + } - pleaf->index = to_int_checked(index); + pleaf->index = (int)index; offset = to_int_checked(endptr - pattern); C2H_SKIP_SPACES(); @@ -848,7 +863,10 @@ static int c2_parse_target(const char *pattern, int offset, c2_ptr_t *presult) { "target.", pleaf->format); } - pleaf->format = to_int_checked(format); + if (format != 8 && format != 16 && format != 32) { + c2_error("Invalid format %ld.", format); + } + pleaf->format = (int)format; } } } @@ -1025,7 +1043,11 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult) c2_error("Invalid octal/hex escape " "sequence."); } - *(ptptnstr++) = to_char_checked(val); + if (val > 127) { + c2_error("Octal/hex escape sequence out " + "of ASCII range."); + } + *(ptptnstr++) = (char)val; offset += 2; break; } diff --git a/src/fuzzer/c2.c b/src/fuzzer/c2.c new file mode 100644 index 00000000..078116d4 --- /dev/null +++ b/src/fuzzer/c2.c @@ -0,0 +1,20 @@ + +#include "c2.h" +#include +#include +#include "config.h" +#include "log.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + log_init_tls(); + if (size == 0) { + return 0; + } + if (data[size - 1] != 0) { + return 0; + } + c2_lptr_t *cond = c2_parse(NULL, (char *)data, NULL); + (void)cond; + (void)size; + return 0; // Values other than 0 and -1 are reserved for future use. +} \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index d7108fba..6057c7d2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -95,3 +95,13 @@ picom = executable('picom', srcs, c_args: cflags, if get_option('unittest') test('picom unittest', picom, args: [ '--unittest' ]) endif + +if cc.has_argument('-fsanitize=fuzzer') + c2_fuzz = executable('c2_fuzz', srcs + ['fuzzer/c2.c'], + c_args: cflags + ['-fsanitize=fuzzer', '-Dmain=__main__'], + link_args: ['-fsanitize=fuzzer'], + dependencies: [ base_deps, deps, test_h_dep ], + build_by_default: false, + install: false, include_directories: picom_inc + ) +endif