c2: add a libfuzzer fuzzer for c2

Add fix some simple bugs discovered by the fuzzer. Two cases of missing
input validation (we have assertions, but assertion failures are not
user friendly). And one case of jump over variable initialization with
goto.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-02-16 23:12:23 +00:00
parent 6715daafc1
commit 4fca4aab07
No known key found for this signature in database
GPG Key ID: D3A4405BE6CC17F4
3 changed files with 60 additions and 8 deletions

View File

@ -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;
}

20
src/fuzzer/c2.c Normal file
View File

@ -0,0 +1,20 @@
#include "c2.h"
#include <stddef.h>
#include <stdint.h>
#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.
}

View File

@ -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