Skip to content

Commit 14ae89c

Browse files
committed
Add fuzzer for binascii module
1 parent 71ede86 commit 14ae89c

3 files changed

Lines changed: 96 additions & 2 deletions

File tree

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
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
1+
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
22

33
PYTHON_CONFIG_PATH=$(CPYTHON_INSTALL_PATH)/bin/python3-config
44
CXXFLAGS += $(shell $(PYTHON_CONFIG_PATH) --cflags)
5-
LDFLAGS += -rdynamic $(shell $(PYTHON_CONFIG_PATH) --ldflags --embed)
5+
LDFLAGS += -rdynamic $(shell $(PYTHON_CONFIG_PATH) --ldflags --embed) $(CPYTHON_MODLIBS) -Wl,--allow-multiple-definition
66

77
fuzzer-html:
88
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:
4040
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"xml.py\"" -ldl $(LDFLAGS) -o fuzzer-xml
4141
fuzzer-zoneinfo:
4242
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"zoneinfo.py\"" -ldl $(LDFLAGS) -o fuzzer-zoneinfo
43+
44+
fuzzer-binascii:
45+
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"binascii.py\"" -ldl $(LDFLAGS) -o fuzzer-binascii

binascii.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
from fuzzeddataprovider import FuzzedDataProvider
2+
import binascii
3+
4+
# Top-level operation constants for FuzzerRunOne
5+
OP_DECODE = 0
6+
OP_ENCODE = 1
7+
OP_CHECKSUM = 2
8+
OP_ROUNDTRIP = 3
9+
10+
# Decode/encode sub-operation constants
11+
CODEC_BASE64_STRICT = 0
12+
CODEC_HEX = 1
13+
CODEC_UU = 2
14+
CODEC_QP = 3
15+
CODEC_BASE64 = 4
16+
CODEC_BASE64_ALT = 5
17+
18+
def op_decode(fdp):
19+
which = fdp.ConsumeIntInRange(CODEC_BASE64_STRICT, CODEC_BASE64_ALT)
20+
strict = fdp.ConsumeBool()
21+
data = fdp.ConsumeBytes(fdp.remaining_bytes())
22+
if which == CODEC_BASE64_STRICT:
23+
if strict:
24+
binascii.a2b_base64(data, strict_mode=True)
25+
else:
26+
binascii.a2b_base64(data)
27+
elif which == CODEC_HEX:
28+
binascii.a2b_hex(data)
29+
elif which == CODEC_UU:
30+
binascii.a2b_uu(data)
31+
elif which == CODEC_QP:
32+
binascii.a2b_qp(data)
33+
elif which == CODEC_BASE64:
34+
binascii.a2b_base64(data)
35+
elif which == CODEC_BASE64_ALT:
36+
binascii.a2b_base64(data)
37+
38+
def op_encode(fdp):
39+
which = fdp.ConsumeIntInRange(CODEC_BASE64_STRICT, CODEC_BASE64_ALT)
40+
newline = fdp.ConsumeBool()
41+
data = fdp.ConsumeBytes(fdp.ConsumeIntInRange(0, 10000))
42+
if not data:
43+
return
44+
if which == CODEC_BASE64_STRICT:
45+
binascii.b2a_base64(data, newline=newline)
46+
elif which == CODEC_HEX:
47+
binascii.b2a_hex(data)
48+
elif which == CODEC_UU:
49+
uu_data = fdp.ConsumeBytes(fdp.ConsumeIntInRange(0, 45))
50+
binascii.b2a_uu(uu_data)
51+
elif which == CODEC_QP:
52+
binascii.b2a_qp(data)
53+
elif which == CODEC_BASE64:
54+
binascii.b2a_base64(data)
55+
elif which == CODEC_BASE64_ALT:
56+
binascii.b2a_base64(data)
57+
58+
def op_checksum(fdp):
59+
use_crc32 = fdp.ConsumeBool()
60+
data = fdp.ConsumeBytes(fdp.remaining_bytes())
61+
if use_crc32:
62+
binascii.crc32(data)
63+
else:
64+
binascii.crc_hqx(data, 0)
65+
66+
def op_roundtrip(fdp):
67+
data = fdp.ConsumeBytes(fdp.remaining_bytes())
68+
hexed = binascii.hexlify(data)
69+
binascii.unhexlify(hexed)
70+
71+
# Fuzzes the binascii module's C implementation (Modules/binascii.c).
72+
# Exercises binary-to-ASCII and ASCII-to-binary conversions for base64,
73+
# hex, UU-encoding, and quoted-printable codecs. Also tests CRC32,
74+
# CRC-HQX checksums, and hexlify/unhexlify roundtrips.
75+
def FuzzerRunOne(FuzzerInput):
76+
if len(FuzzerInput) < 1 or len(FuzzerInput) > 0x100000:
77+
return
78+
fdp = FuzzedDataProvider(FuzzerInput)
79+
op = fdp.ConsumeIntInRange(OP_DECODE, OP_ROUNDTRIP)
80+
try:
81+
if op == OP_DECODE:
82+
op_decode(fdp)
83+
elif op == OP_ENCODE:
84+
op_encode(fdp)
85+
elif op == OP_CHECKSUM:
86+
op_checksum(fdp)
87+
else:
88+
op_roundtrip(fdp)
89+
except Exception:
90+
pass

fuzz_targets.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
ast ast.py
2+
binascii binascii.py
23
configparser configparser.py
34
csv csv.py
45
decode decode.py

0 commit comments

Comments
 (0)