Skip to content

Commit 947303c

Browse files
committed
Add fuzzer for mmap module
1 parent 71ede86 commit 947303c

File tree

3 files changed

+106
-2
lines changed

3 files changed

+106
-2
lines changed

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-mmap
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-mmap:
45+
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"mmap.py\"" -ldl $(LDFLAGS) -o fuzzer-mmap

fuzz_targets.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ email email.py
77
html html.py
88
httpclient httpclient.py
99
json json.py
10+
mmap mmap.py
1011
plistlib plist.py
1112
re re.py
1213
tarfile tarfile.py

mmap.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
from fuzzeddataprovider import FuzzedDataProvider
2+
import os
3+
import mmap
4+
import tempfile
5+
6+
OP_FIND = 0
7+
OP_RFIND = 1
8+
OP_READ = 2
9+
OP_READLINE = 3
10+
OP_SEEK = 4
11+
OP_GETITEM = 5
12+
OP_WRITE = 6
13+
OP_SETITEM = 7
14+
OP_MOVE = 8
15+
OP_FLUSH = 9
16+
17+
_OP_MAX = OP_FLUSH
18+
19+
20+
# Fuzzes the mmap C module (Modules/mmapmodule.c). Creates a temporary
21+
# file-backed mmap and exercises find, rfind, seek, read, readline,
22+
# getitem, write, setitem, move, and flush operations with fuzzed
23+
# offsets, sizes, and byte content.
24+
def FuzzerRunOne(FuzzerInput):
25+
if len(FuzzerInput) < 1 or len(FuzzerInput) > 0x10000:
26+
return
27+
fdp = FuzzedDataProvider(FuzzerInput)
28+
init_size = (
29+
fdp.ConsumeIntInRange(1, min(fdp.remaining_bytes(), 4096))
30+
if fdp.remaining_bytes() > 0
31+
else 0
32+
)
33+
if init_size == 0:
34+
return
35+
init_data = fdp.ConsumeBytes(init_size)
36+
tmpname = None
37+
try:
38+
with tempfile.NamedTemporaryFile(delete=False) as tmp:
39+
tmpname = tmp.name
40+
tmp.write(init_data)
41+
tmp.flush()
42+
43+
with open(tmpname, "r+b") as f:
44+
mm = mmap.mmap(f.fileno(), 0)
45+
num_ops = fdp.ConsumeIntInRange(1, 10)
46+
for _ in range(num_ops):
47+
if fdp.remaining_bytes() == 0:
48+
break
49+
op = fdp.ConsumeIntInRange(0, _OP_MAX)
50+
if op == OP_FIND:
51+
needle = fdp.ConsumeBytes(
52+
fdp.ConsumeIntInRange(1, min(fdp.remaining_bytes(), 20))
53+
)
54+
mm.find(needle)
55+
elif op == OP_RFIND:
56+
needle = fdp.ConsumeBytes(
57+
fdp.ConsumeIntInRange(1, min(fdp.remaining_bytes(), 20))
58+
)
59+
mm.rfind(needle)
60+
elif op == OP_READ:
61+
mm.seek(0)
62+
mm.read(fdp.ConsumeIntInRange(0, len(mm)))
63+
elif op == OP_READLINE:
64+
mm.seek(0)
65+
mm.readline()
66+
elif op == OP_SEEK:
67+
pos = fdp.ConsumeIntInRange(0, max(0, len(mm) - 1))
68+
mm.seek(pos)
69+
elif op == OP_GETITEM:
70+
if len(mm) > 0:
71+
idx = fdp.ConsumeIntInRange(0, len(mm) - 1)
72+
_ = mm[idx]
73+
elif op == OP_WRITE:
74+
data = fdp.ConsumeBytes(
75+
fdp.ConsumeIntInRange(1, min(fdp.remaining_bytes(), 50))
76+
)
77+
pos = fdp.ConsumeIntInRange(0, max(0, len(mm) - len(data)))
78+
mm.seek(pos)
79+
mm.write(data)
80+
elif op == OP_SETITEM:
81+
if len(mm) > 0:
82+
idx = fdp.ConsumeIntInRange(0, len(mm) - 1)
83+
mm[idx] = fdp.ConsumeInt(1)
84+
elif op == OP_MOVE:
85+
if len(mm) > 1:
86+
count = fdp.ConsumeIntInRange(1, len(mm) // 2)
87+
src = fdp.ConsumeIntInRange(0, len(mm) - count)
88+
dest = fdp.ConsumeIntInRange(0, len(mm) - count)
89+
mm.move(dest, src, count)
90+
elif op == OP_FLUSH:
91+
mm.flush()
92+
mm.close()
93+
except Exception:
94+
pass
95+
finally:
96+
if tmpname:
97+
try:
98+
os.unlink(tmpname)
99+
except Exception:
100+
pass

0 commit comments

Comments
 (0)