diff --git a/Makefile b/Makefile index 01df3e8..9623816 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -all: fuzzer-binascii fuzzer-html fuzzer-email fuzzer-httpclient fuzzer-json fuzzer-difflib fuzzer-csv fuzzer-decode fuzzer-ast fuzzer-tarfile fuzzer-tarfile-hypothesis fuzzer-zipfile fuzzer-zipfile-hypothesis fuzzer-re fuzzer-configparser fuzzer-tomllib fuzzer-plistlib fuzzer-xml fuzzer-zoneinfo +all: fuzzer-binascii fuzzer-html fuzzer-email fuzzer-httpclient fuzzer-json fuzzer-difflib fuzzer-csv fuzzer-decode fuzzer-ast fuzzer-tarfile fuzzer-tarfile-hypothesis fuzzer-zipfile fuzzer-zipfile-hypothesis fuzzer-re fuzzer-configparser fuzzer-tomllib fuzzer-plistlib fuzzer-xml fuzzer-zoneinfo fuzzer-datetime PYTHON_CONFIG_PATH=$(CPYTHON_INSTALL_PATH)/bin/python3-config CXXFLAGS += $(shell $(PYTHON_CONFIG_PATH) --cflags) @@ -42,3 +42,6 @@ fuzzer-xml: clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"xml.py\"" -ldl $(LDFLAGS) -o fuzzer-xml fuzzer-zoneinfo: clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"zoneinfo.py\"" -ldl $(LDFLAGS) -o fuzzer-zoneinfo + +fuzzer-datetime: + clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"datetime.py\"" -ldl $(LDFLAGS) -o fuzzer-datetime diff --git a/corp-datetime/date_0 b/corp-datetime/date_0 new file mode 100644 index 0000000..8ace412 Binary files /dev/null and b/corp-datetime/date_0 differ diff --git a/corp-datetime/date_1 b/corp-datetime/date_1 new file mode 100644 index 0000000..032c919 Binary files /dev/null and b/corp-datetime/date_1 differ diff --git a/corp-datetime/date_2 b/corp-datetime/date_2 new file mode 100644 index 0000000..6bcac16 Binary files /dev/null and b/corp-datetime/date_2 differ diff --git a/corp-datetime/date_3 b/corp-datetime/date_3 new file mode 100644 index 0000000..54719f4 Binary files /dev/null and b/corp-datetime/date_3 differ diff --git a/corp-datetime/datetime_0 b/corp-datetime/datetime_0 new file mode 100644 index 0000000..ef057ee --- /dev/null +++ b/corp-datetime/datetime_0 @@ -0,0 +1 @@ +2024-01-15T10:30 \ No newline at end of file diff --git a/corp-datetime/datetime_1 b/corp-datetime/datetime_1 new file mode 100644 index 0000000..7d23e84 --- /dev/null +++ b/corp-datetime/datetime_1 @@ -0,0 +1 @@ +2024-01-15 10:30:00 \ No newline at end of file diff --git a/corp-datetime/datetime_2 b/corp-datetime/datetime_2 new file mode 100644 index 0000000..e67caaa --- /dev/null +++ b/corp-datetime/datetime_2 @@ -0,0 +1 @@ +2024-01-15T10:30:00.123456 \ No newline at end of file diff --git a/corp-datetime/datetime_3 b/corp-datetime/datetime_3 new file mode 100644 index 0000000..fa07490 --- /dev/null +++ b/corp-datetime/datetime_3 @@ -0,0 +1 @@ +2024-01-15T10:30:00+01:00 \ No newline at end of file diff --git a/corp-datetime/datetime_4 b/corp-datetime/datetime_4 new file mode 100644 index 0000000..3aee0de --- /dev/null +++ b/corp-datetime/datetime_4 @@ -0,0 +1 @@ +2024-01-15T10:30:00.123456-05:30 \ No newline at end of file diff --git a/corp-datetime/datetime_5 b/corp-datetime/datetime_5 new file mode 100644 index 0000000..d7091cf --- /dev/null +++ b/corp-datetime/datetime_5 @@ -0,0 +1 @@ +0001-01-01T00:00:00 \ No newline at end of file diff --git a/corp-datetime/datetime_6 b/corp-datetime/datetime_6 new file mode 100644 index 0000000..7cae748 --- /dev/null +++ b/corp-datetime/datetime_6 @@ -0,0 +1 @@ +9999-12-31T23:59:59.999999+00:00 \ No newline at end of file diff --git a/corp-datetime/datetime_7 b/corp-datetime/datetime_7 new file mode 100644 index 0000000..bbd0b36 --- /dev/null +++ b/corp-datetime/datetime_7 @@ -0,0 +1 @@ +2024-06-01T12:00:00.000001+02:00 \ No newline at end of file diff --git a/corp-datetime/time_0 b/corp-datetime/time_0 new file mode 100644 index 0000000..c75d29d --- /dev/null +++ b/corp-datetime/time_0 @@ -0,0 +1 @@ +10:30 \ No newline at end of file diff --git a/corp-datetime/time_1 b/corp-datetime/time_1 new file mode 100644 index 0000000..c649057 --- /dev/null +++ b/corp-datetime/time_1 @@ -0,0 +1 @@ +10:30:00 \ No newline at end of file diff --git a/corp-datetime/time_2 b/corp-datetime/time_2 new file mode 100644 index 0000000..348f88e --- /dev/null +++ b/corp-datetime/time_2 @@ -0,0 +1 @@ +10:30:00.123456 \ No newline at end of file diff --git a/corp-datetime/time_3 b/corp-datetime/time_3 new file mode 100644 index 0000000..5ddcd9e --- /dev/null +++ b/corp-datetime/time_3 @@ -0,0 +1 @@ +10:30:00,5 \ No newline at end of file diff --git a/corp-datetime/time_4 b/corp-datetime/time_4 new file mode 100644 index 0000000..188833d --- /dev/null +++ b/corp-datetime/time_4 @@ -0,0 +1 @@ +00:00 \ No newline at end of file diff --git a/corp-datetime/time_5 b/corp-datetime/time_5 new file mode 100644 index 0000000..15612f2 --- /dev/null +++ b/corp-datetime/time_5 @@ -0,0 +1 @@ +23:59:59.999999 \ No newline at end of file diff --git a/corp-datetime/time_6 b/corp-datetime/time_6 new file mode 100644 index 0000000..bd8c2a4 --- /dev/null +++ b/corp-datetime/time_6 @@ -0,0 +1 @@ +10:30+01:00 \ No newline at end of file diff --git a/corp-datetime/time_7 b/corp-datetime/time_7 new file mode 100644 index 0000000..e492887 --- /dev/null +++ b/corp-datetime/time_7 @@ -0,0 +1 @@ +10:30:00-05:30 \ No newline at end of file diff --git a/corp-datetime/time_8 b/corp-datetime/time_8 new file mode 100644 index 0000000..dd2c6ce --- /dev/null +++ b/corp-datetime/time_8 @@ -0,0 +1 @@ +10:30:00.123456+01:00:30 \ No newline at end of file diff --git a/datetime.py b/datetime.py new file mode 100644 index 0000000..1663b43 --- /dev/null +++ b/datetime.py @@ -0,0 +1,45 @@ +"""Fuzz the C ISO-8601 fast parsers and date/time arithmetic. + +date, time and datetime fromisoformat() are implemented in C +(Modules/_datetimemodule.c) and parse attacker-controlled strings. +Two properties are exercised: isoformat() must round-trip through +fromisoformat (documented inverse -- a mismatch is a logic bug and +raises AssertionError), and fuzzed timedelta shifts drive the C +normalisation and overflow-checking paths. Invalid ISO strings are +expected and raise ValueError/TypeError; time objects reject +/- with +TypeError. +""" +from datetime import date, datetime, time, timedelta + + +def FuzzerRunOne(FuzzerInput): + if len(FuzzerInput) < 3: + return + op = FuzzerInput[0] + amount = FuzzerInput[1] + data = FuzzerInput[2:].decode("utf-8", "replace") + if op % 3 == 0: + parse = date.fromisoformat + elif op % 3 == 1: + parse = time.fromisoformat + else: + parse = datetime.fromisoformat + try: + parsed = parse(data) + except (ValueError, TypeError): + return + + # Round-trip property: fromisoformat is the documented inverse of + # isoformat(), for all three types. + reparsed = type(parsed).fromisoformat(parsed.isoformat()) + if reparsed != parsed: + raise AssertionError( + "isoformat round-trip mismatch: %r -> %r" % (parsed, parsed.isoformat()) + ) + + delta = timedelta(amount % 30, amount % 60, amount % 1000000) + try: + parsed + delta + parsed - delta + except (TypeError, OverflowError): + pass diff --git a/fuzz_targets.txt b/fuzz_targets.txt index b016889..2f1aea5 100644 --- a/fuzz_targets.txt +++ b/fuzz_targets.txt @@ -2,6 +2,7 @@ ast ast.py binascii binascii.py configparser configparser.py csv csv.py +datetime datetime.py decode decode.py difflib difflib.py email email.py diff --git a/fuzzer-datetime.dict b/fuzzer-datetime.dict new file mode 100644 index 0000000..6824d4d --- /dev/null +++ b/fuzzer-datetime.dict @@ -0,0 +1,33 @@ +# ISO-8601 tokens for date/time/datetime.fromisoformat +"T" +"Z" +"z" +"+01:00" +"+01:00:30" +"-05:30" +"+0000" +"+01" +"2024-01-15" +"2024-01-15T10:30" +"2024-01-15 10:30:00" +"10:30" +"10:30:00" +"10:30:00.123456" +"10:30:00,5" +".123456" +",123" +"24:00" +"00:00" +"W" +"-W" +"2024-W03-1" +"2024-W03" +"2024-021" +"0001-01-01" +"9999-12-31" +"23:59:59.999999" +"+23:59" +"-23:59" +"hh" +"mm" +"ss"