diff --git a/Makefile b/Makefile index 9103a1c..7bbbca4 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -all : 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-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-binascii PYTHON_CONFIG_PATH=$(CPYTHON_INSTALL_PATH)/bin/python3-config CXXFLAGS += $(shell $(PYTHON_CONFIG_PATH) --cflags) -LDFLAGS += -rdynamic $(shell $(PYTHON_CONFIG_PATH) --ldflags --embed) +LDFLAGS += -rdynamic $(shell $(PYTHON_CONFIG_PATH) --ldflags --embed) $(CPYTHON_MODLIBS) -Wl,--allow-multiple-definition fuzzer-html: clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"html.py\"" -ldl $(LDFLAGS) -o fuzzer-html @@ -40,3 +40,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-binascii: + clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"binascii.py\"" -ldl $(LDFLAGS) -o fuzzer-binascii diff --git a/binascii.py b/binascii.py new file mode 100644 index 0000000..97753ae --- /dev/null +++ b/binascii.py @@ -0,0 +1,95 @@ +from fuzzeddataprovider import FuzzedDataProvider +import binascii + +# Top-level operation constants for FuzzerRunOne +OP_DECODE = 0 +OP_ENCODE = 1 +OP_CHECKSUM = 2 +OP_ROUNDTRIP = 3 + +# Decode/encode sub-operation constants +CODEC_BASE64_STRICT = 0 +CODEC_HEX = 1 +CODEC_UU = 2 +CODEC_QP = 3 +CODEC_BASE64 = 4 +CODEC_BASE64_ALT = 5 + + +def op_decode(fdp): + which = fdp.ConsumeIntInRange(CODEC_BASE64_STRICT, CODEC_BASE64_ALT) + strict = fdp.ConsumeBool() + data = fdp.ConsumeBytes(fdp.remaining_bytes()) + if which == CODEC_BASE64_STRICT: + if strict: + binascii.a2b_base64(data, strict_mode=True) + else: + binascii.a2b_base64(data) + elif which == CODEC_HEX: + binascii.a2b_hex(data) + elif which == CODEC_UU: + binascii.a2b_uu(data) + elif which == CODEC_QP: + binascii.a2b_qp(data) + elif which == CODEC_BASE64: + binascii.a2b_base64(data) + elif which == CODEC_BASE64_ALT: + binascii.a2b_base64(data) + + +def op_encode(fdp): + which = fdp.ConsumeIntInRange(CODEC_BASE64_STRICT, CODEC_BASE64_ALT) + newline = fdp.ConsumeBool() + data = fdp.ConsumeBytes(fdp.ConsumeIntInRange(0, 10000)) + if not data: + return + if which == CODEC_BASE64_STRICT: + binascii.b2a_base64(data, newline=newline) + elif which == CODEC_HEX: + binascii.b2a_hex(data) + elif which == CODEC_UU: + uu_data = fdp.ConsumeBytes(fdp.ConsumeIntInRange(0, 45)) + binascii.b2a_uu(uu_data) + elif which == CODEC_QP: + binascii.b2a_qp(data) + elif which == CODEC_BASE64: + binascii.b2a_base64(data) + elif which == CODEC_BASE64_ALT: + binascii.b2a_base64(data) + + +def op_checksum(fdp): + use_crc32 = fdp.ConsumeBool() + data = fdp.ConsumeBytes(fdp.remaining_bytes()) + if use_crc32: + binascii.crc32(data) + else: + binascii.crc_hqx(data, 0) + + +def op_roundtrip(fdp): + data = fdp.ConsumeBytes(fdp.remaining_bytes()) + hexed = binascii.hexlify(data) + binascii.unhexlify(hexed) + + +# Fuzzes the binascii module's C implementation (Modules/binascii.c). +# Exercises binary-to-ASCII and ASCII-to-binary conversions for base64, +# hex, UU-encoding, and quoted-printable codecs. Also tests CRC32, +# CRC-HQX checksums, and hexlify/unhexlify roundtrips. +def FuzzerRunOne(FuzzerInput): + if len(FuzzerInput) < 1 or len(FuzzerInput) > 0x100000: + return + fdp = FuzzedDataProvider(FuzzerInput) + op = fdp.ConsumeIntInRange(OP_DECODE, OP_ROUNDTRIP) + try: + if op == OP_DECODE: + op_decode(fdp) + elif op == OP_ENCODE: + op_encode(fdp) + elif op == OP_CHECKSUM: + op_checksum(fdp) + else: + op_roundtrip(fdp) + except Exception: + pass diff --git a/fuzz_targets.txt b/fuzz_targets.txt index 8710a5f..b016889 100644 --- a/fuzz_targets.txt +++ b/fuzz_targets.txt @@ -1,4 +1,5 @@ ast ast.py +binascii binascii.py configparser configparser.py csv csv.py decode decode.py