mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 22:53:24 +00:00
Compare commits
462 Commits
Author | SHA1 | Date | |
---|---|---|---|
900b801a46 | |||
8c9b905a1c | |||
a7c763434e | |||
1a9a28aeb4 | |||
ba99a8c428 | |||
f516b9829d | |||
e2ac0b0054 | |||
c27c357e12 | |||
b28077c527 | |||
0fb86cd3af | |||
6921b45299 | |||
d3c6833c13 | |||
8b42dfc25f | |||
d0e1d06cd3 | |||
8130b69a91 | |||
e2b74c9521 | |||
1c66a0d1ac | |||
bc127da1be | |||
b276faf64d | |||
f28e412ffe | |||
257d7b28f2 | |||
94d7f36e2f | |||
c4d9249775 | |||
7f38638a56 | |||
f986511e21 | |||
4c0158d678 | |||
318aa8cdf9 | |||
1c2b9de185 | |||
d12049ba86 | |||
dd9ef0cf22 | |||
b87f030f2e | |||
b056c5b9e1 | |||
a286787c0d | |||
8501a1d945 | |||
2db492d52f | |||
3fbee16794 | |||
c0152c1de9 | |||
a32895f1fa | |||
cb7ec64741 | |||
cd0c04a5de | |||
064a580cc8 | |||
560cd44c9a | |||
fdab500673 | |||
2fbe03abfe | |||
8aa3b42533 | |||
83fca1ad38 | |||
04bb316a46 | |||
19d8288c7c | |||
c0c2c696c1 | |||
d6f27adcd0 | |||
b08f13c9fe | |||
6f381d346b | |||
78191557b2 | |||
00e5449ad6 | |||
a63da7cdf6 | |||
af0d023b3a | |||
0975c8ddde | |||
7d017f1cb1 | |||
a16bc3f36c | |||
f9afbc822c | |||
1c7176bd96 | |||
ad44e30cbf | |||
0d495e0471 | |||
9951c38515 | |||
ee480aeb7a | |||
c8d1b66af3 | |||
d25efff179 | |||
91974bfae2 | |||
8618fbc0c2 | |||
16cc444ae5 | |||
a9900f02cb | |||
e82de006a7 | |||
4a923e59fd | |||
20348a63bd | |||
cafcb343b1 | |||
588dda3e84 | |||
a17d1daab8 | |||
affe7cf5b4 | |||
fa1ac051eb | |||
f21cc2da58 | |||
8c1ab19ebe | |||
2e7f191f3b | |||
8090c82c63 | |||
f610f53838 | |||
0012f710d8 | |||
be00ea9f00 | |||
d0df78f07a | |||
7e1dc85450 | |||
8152def40e | |||
e6ed31d550 | |||
77758a1343 | |||
ea1fbb75b3 | |||
d62a885f0f | |||
55d534cd6d | |||
cee764689c | |||
d02390e62e | |||
1f878f1b7c | |||
ff1e0580b0 | |||
4730fa4226 | |||
50fb923691 | |||
300fc1f002 | |||
4ff40ee6fd | |||
c3d5f3f471 | |||
45a7d65207 | |||
b8d1f16979 | |||
c699aa252d | |||
7c27fc7cfe | |||
46b9efbf7d | |||
92d1a60096 | |||
f90fafc07a | |||
59c2198532 | |||
c7654c028d | |||
ccc7ab5944 | |||
06afa48e02 | |||
816334000a | |||
2573ccb66e | |||
767b990af6 | |||
1631e5988f | |||
3ee3b5c384 | |||
7f7d5ff29b | |||
6dcd0aa089 | |||
c47221db7c | |||
d6bb210410 | |||
c2a026f68f | |||
2a97350754 | |||
9004be20b8 | |||
dffd6537ae | |||
25d7d65216 | |||
7a32331c99 | |||
b27e861a51 | |||
875c3902f0 | |||
bedb38e216 | |||
ef0c236427 | |||
b6d1247e7d | |||
62e63d1125 | |||
9e4449bad2 | |||
6d4a56e481 | |||
221439fc7a | |||
fca39a6ec3 | |||
9476204da0 | |||
919108ee57 | |||
8204bf6915 | |||
b9e361df46 | |||
19fc27a3f7 | |||
2357daebe0 | |||
f3995d5225 | |||
ea6d182b4a | |||
adeaa714ce | |||
231a4b1937 | |||
977e08cda1 | |||
6b1d6a9055 | |||
4d9d8aaf16 | |||
c150d8e17d | |||
61e97a8ceb | |||
3f2e03aaf9 | |||
406e4880c7 | |||
22b7d370bc | |||
ec27e96486 | |||
fcca917f4f | |||
5bf01afd6b | |||
0a9916deab | |||
b1730d99b6 | |||
6d45b286f8 | |||
673463ff1c | |||
f580fefc5f | |||
320d4b7ef8 | |||
19bd2984d5 | |||
7d29418db5 | |||
4d984d6e2b | |||
421b6492d3 | |||
062f883160 | |||
a76ff5e798 | |||
e9f49527e9 | |||
6f4767ea81 | |||
d28b1418a2 | |||
d10b85421d | |||
6876ab7901 | |||
b1649f2fdb | |||
701299eefd | |||
90e929ea17 | |||
24dc7b569c | |||
7cb8ccc960 | |||
0c4f8934c7 | |||
cd0cb1e731 | |||
52631d925d | |||
d40f935b4e | |||
b418a87340 | |||
04f2a2dd09 | |||
aa1c58a077 | |||
cca5538747 | |||
c4be2ec32f | |||
83a2a8aa14 | |||
6c70d68783 | |||
6d5784e955 | |||
5f7009d6e9 | |||
48bce88050 | |||
f43116d9e0 | |||
876a528156 | |||
8a0e9c8915 | |||
b083016304 | |||
30c93d1321 | |||
e30a17be91 | |||
c340a022e2 | |||
06219b4d56 | |||
c5b8f4250e | |||
779cb5d942 | |||
fb1a41f5af | |||
8352f0a89f | |||
9935190c7b | |||
e3ee26262f | |||
737c13b460 | |||
9836598d65 | |||
63509fb696 | |||
d1c44e12a8 | |||
f78ed6eabc | |||
64c942d0c9 | |||
50e343a0d0 | |||
55719ab23b | |||
d12c5edd59 | |||
1b82d6b904 | |||
61201fbbb8 | |||
b9458e72e7 | |||
5045f9e615 | |||
6cd8a0168f | |||
448c6c212d | |||
05f4762894 | |||
0a06e36788 | |||
9b1f80c277 | |||
787a332a73 | |||
7d85047fd9 | |||
fa8dc2028f | |||
619aa70414 | |||
247e8241b4 | |||
0bb64e4bc9 | |||
7b84ec97e2 | |||
20a6cdabad | |||
0d286c9e19 | |||
db94ec9cad | |||
05dfb70787 | |||
7f2becba72 | |||
13b27bb59e | |||
ecdbdc3164 | |||
788e70a01a | |||
938ed60ea9 | |||
5b9d2cc38b | |||
e305bc15d3 | |||
0b12c7e0cc | |||
4bd492f212 | |||
be8393f201 | |||
aec90c7227 | |||
1960352310 | |||
03169b2b67 | |||
dee51213a7 | |||
1d2de1cb6d | |||
5ed187b517 | |||
a845852b98 | |||
9513397336 | |||
57fa87ce5e | |||
c6a2cf88bf | |||
8461f860eb | |||
7395223512 | |||
1121af301b | |||
b9c1536283 | |||
6691ce943a | |||
1dba3a276f | |||
3c8016e071 | |||
b64dd0a1ec | |||
55f758a168 | |||
bd631c73a2 | |||
6cbe58ff55 | |||
c71d487a4c | |||
939171952d | |||
161905c2fc | |||
5ff21c9aad | |||
112d90656b | |||
bc11bd7661 | |||
6b71ca7809 | |||
eb0b8b2c5c | |||
6223ddf6d2 | |||
920c7fe71a | |||
4ff2673895 | |||
891b7f48f0 | |||
5df3cdbc0b | |||
57466909e4 | |||
55c9c4ff19 | |||
fe202b5fee | |||
c5e511302f | |||
7c349b6cde | |||
fc38904e25 | |||
eee2521eb4 | |||
192d4817e0 | |||
58e4070573 | |||
2ecf28440f | |||
757184e611 | |||
27b18e6267 | |||
f1ee7bc9cd | |||
969541b54f | |||
ec07f531f8 | |||
56b5983b61 | |||
f17ea60a30 | |||
68634964ef | |||
d21804bdd1 | |||
5a527046a5 | |||
b2a8765b1f | |||
106309492c | |||
58c5e2b96c | |||
5842ba87e5 | |||
5069551778 | |||
0606d95f86 | |||
0e35e56cc9 | |||
fc860872d6 | |||
735d647e48 | |||
73ab495b5d | |||
d1cab470bb | |||
992349e48a | |||
950b90abcd | |||
f3b15d6340 | |||
0134a23046 | |||
7c296f099f | |||
919e6226d3 | |||
a85f0c0ef9 | |||
6457e2ea30 | |||
542233e1ce | |||
8e4823e7ed | |||
f27c504f29 | |||
9776e402c3 | |||
4cabb81996 | |||
42465480ef | |||
f27f109880 | |||
fa9e256e09 | |||
78952e8440 | |||
8b543df04c | |||
e64c3f8653 | |||
f590973387 | |||
36338ad08b | |||
73a36ffda3 | |||
cdf93f4d1f | |||
a0d996558b | |||
21e75d73a6 | |||
cc1d41f59d | |||
9530b4c9d4 | |||
f1998bb53b | |||
0e3c82e2ea | |||
c22b06a27d | |||
1d1aa3edec | |||
50f6b38530 | |||
0cd932c4b5 | |||
a635aa8cba | |||
00577bb32d | |||
6aaba974b6 | |||
6459707f24 | |||
870e22246a | |||
66c2bb3994 | |||
a482b817af | |||
6f433b5d73 | |||
2843b7eb02 | |||
6ed9b6d631 | |||
6f018b3d80 | |||
1318636ae7 | |||
29f48ab3e7 | |||
2c2a0471cd | |||
68f5c4811e | |||
fe6d3990ce | |||
2b143688a6 | |||
f37f0b4ee4 | |||
bd5ccc6977 | |||
e0b23dd53d | |||
54890db08e | |||
6c4b2f0c8e | |||
bed20d40b1 | |||
ea2f112016 | |||
f639668032 | |||
1709eb59a8 | |||
bbdcfb0e8e | |||
cab4609e1a | |||
feed691dc0 | |||
e4f7a4738e | |||
625df13d0e | |||
a3c038efd6 | |||
4f3812f00d | |||
887d104dae | |||
47954cd04c | |||
a441f517e7 | |||
9cb3fe98dd | |||
e6f15f02e1 | |||
65b99d25e1 | |||
7b86d735df | |||
b56b24d251 | |||
c2383761cb | |||
f87a669aa3 | |||
8489112ab1 | |||
ebd6d4b8bb | |||
125027f5bf | |||
9cac7ced05 | |||
ecaddc09e8 | |||
287edf2754 | |||
7765d4ac33 | |||
6a4b5807b6 | |||
72d248ae57 | |||
c78643f566 | |||
0b53a5a8aa | |||
80e1a95378 | |||
5fa1a9c365 | |||
522da5e9b5 | |||
c7e919333e | |||
c64813b7d5 | |||
b96047d7b0 | |||
604cf2cf80 | |||
c7c66bd0d6 | |||
40991801bd | |||
fd780e8eba | |||
96dc77e410 | |||
60b92dcef3 | |||
12a88c52df | |||
be3c665eee | |||
f905087e8e | |||
99cf15bd30 | |||
5c239d9207 | |||
c4d576b4e0 | |||
efa2120935 | |||
967b81736d | |||
f4346e423d | |||
a60003e3cf | |||
1c9925c7d7 | |||
635cd7374e | |||
fb52b8edf8 | |||
30861b5d54 | |||
b2a01936c3 | |||
8dbfcde798 | |||
7ad694716b | |||
e93ab23823 | |||
79a24685b2 | |||
cad7536036 | |||
1ddfb1fec2 | |||
ae8df744ee | |||
aaaa96af6d | |||
2e2a3a2718 | |||
eee4be90c1 | |||
5fe21c3797 | |||
4eaacfb095 | |||
82b0cf0540 | |||
5a352adb19 | |||
9afba51ec1 | |||
99402aa31c | |||
af11b80fda | |||
10db3a35cf | |||
af44b07b31 | |||
9b433e2d8c | |||
85e14cf8d1 | |||
f2f417325f | |||
3e18b1a10c | |||
1d3e885441 | |||
0c69d0a0d8 | |||
bbffece7d7 | |||
2956b9cc4c | |||
9160805f4a | |||
50e2f9d46c | |||
223b14134c | |||
f5a672f9d8 | |||
9ce45665d7 | |||
10883b1392 | |||
d206d5fc46 |
@ -21,12 +21,15 @@ import os
|
||||
# import re # TODO: for future use
|
||||
import shutil
|
||||
import importlib.metadata
|
||||
import hashlib
|
||||
|
||||
# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use
|
||||
|
||||
CURRENT_LLVM = os.getenv('LLVM_VERSION', 18)
|
||||
CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "")
|
||||
|
||||
FORMAT_CACHE_DIR = '.format-cache'
|
||||
os.makedirs(FORMAT_CACHE_DIR, exist_ok=True)
|
||||
|
||||
def check_clang_format_pip_version():
|
||||
"""
|
||||
@ -69,6 +72,8 @@ to install via pip.")
|
||||
if CLANG_FORMAT_PIP:
|
||||
CLANG_FORMAT_BIN = shutil.which("clang-format")
|
||||
|
||||
CLANG_FORMAT_VERSION = subprocess.check_output([CLANG_FORMAT_BIN, '--version'])
|
||||
|
||||
COLUMN_LIMIT = 80
|
||||
for line in fmt.split("\n"):
|
||||
line = line.split(":")
|
||||
@ -86,9 +91,10 @@ def custom_format(filename):
|
||||
out = ""
|
||||
|
||||
for line in src.split("\n"):
|
||||
define_start = False
|
||||
if line.lstrip().startswith("#"):
|
||||
if line[line.find("#") + 1:].lstrip().startswith("define"):
|
||||
in_define = True
|
||||
define_start = True
|
||||
|
||||
if (
|
||||
"/*" in line
|
||||
@ -126,9 +132,7 @@ def custom_format(filename):
|
||||
and last_line.strip() != ""
|
||||
):
|
||||
line = (" " * define_padding + "\\" if in_define else "") + "\n" + line
|
||||
|
||||
if not line.endswith("\\"):
|
||||
in_define = False
|
||||
in_define = (define_start or in_define) and line.endswith("\\")
|
||||
|
||||
out += line + "\n"
|
||||
last_line = line
|
||||
@ -136,6 +140,38 @@ def custom_format(filename):
|
||||
return out
|
||||
|
||||
|
||||
def hash_code_and_formatter(code):
|
||||
hasher = hashlib.sha256()
|
||||
|
||||
hasher.update(code.encode())
|
||||
hasher.update(CLANG_FORMAT_VERSION)
|
||||
with open(__file__, 'rb') as f:
|
||||
hasher.update(f.read())
|
||||
|
||||
return hasher.hexdigest()
|
||||
|
||||
|
||||
def custom_format_cached(filename):
|
||||
filename_hash = hashlib.sha256(filename.encode()).hexdigest()
|
||||
cache_file = os.path.join(FORMAT_CACHE_DIR, filename_hash)
|
||||
|
||||
if os.path.exists(cache_file):
|
||||
with open(filename) as f:
|
||||
code = f.read()
|
||||
code_hash = hash_code_and_formatter(code)
|
||||
with open(cache_file) as f:
|
||||
if f.read() == code_hash:
|
||||
return code
|
||||
|
||||
code = custom_format(filename)
|
||||
|
||||
code_hash = hash_code_and_formatter(code)
|
||||
with open(cache_file, 'w') as f:
|
||||
f.write(code_hash)
|
||||
|
||||
return code
|
||||
|
||||
|
||||
args = sys.argv[1:]
|
||||
if len(args) == 0:
|
||||
print("Usage: ./format.py [-i] <filename>")
|
||||
@ -151,7 +187,7 @@ if args[0] == "-i":
|
||||
args = args[1:]
|
||||
|
||||
for filename in args:
|
||||
code = custom_format(filename)
|
||||
code = custom_format_cached(filename)
|
||||
if in_place:
|
||||
with open(filename, "w") as f:
|
||||
f.write(code)
|
||||
|
86
.github/workflows/ci.yml
vendored
86
.github/workflows/ci.yml
vendored
@ -9,29 +9,101 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: "${{ matrix.os }}"
|
||||
check-compiler-passes-old:
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-20.04]
|
||||
version: [14, 15]
|
||||
env:
|
||||
AFL_SKIP_CPUFREQ: 1
|
||||
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: update
|
||||
run: sudo apt-get update && sudo apt-get upgrade -y
|
||||
- name: debug
|
||||
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
|
||||
- name: install packages
|
||||
run: sudo apt-get install -y -m -f build-essential gcc-10 g++-10 git libtool libtool-bin automake flex bison libglib2.0-0 clang-12 llvm-12-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-10-plugin-dev
|
||||
run: sudo apt-get install -y -m -f build-essential git libtool libtool-bin automake flex bison libglib2.0-0 libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-12-plugin-dev
|
||||
- name: install llvm-tools
|
||||
run: sudo apt install -y clang-${{ matrix.version }} llvm-${{ matrix.version }}
|
||||
- name: install clang-rt (for llvm 15)
|
||||
# because ubuntu-22.04 already has this package
|
||||
if: matrix.version != '15'
|
||||
run: sudo apt install -y libclang-${{ matrix.version }}-dev
|
||||
- name: compiler installed
|
||||
run: gcc -v; echo; clang -v
|
||||
- name: build afl++
|
||||
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-${{ matrix.version }}; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} all
|
||||
- name: Check llvm passes
|
||||
run: make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} llvm-build-test || exit 1
|
||||
- name: run tests
|
||||
run: sudo -E ./afl-system-config; make tests
|
||||
check-compiler-passes-new:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
version: [16, 17, 18, 19, 20]
|
||||
env:
|
||||
AFL_SKIP_CPUFREQ: 1
|
||||
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: update
|
||||
run: sudo apt-get update && sudo apt-get upgrade -y
|
||||
- name: debug
|
||||
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
|
||||
- name: install packages
|
||||
run: sudo apt-get install -y -m -f build-essential git libtool libtool-bin automake flex bison libglib2.0-0 libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-12-plugin-dev
|
||||
- name: install llvm-tools (20)
|
||||
if: matrix.version == '20'
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh ${{ matrix.version }}
|
||||
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{ matrix.version }} 200
|
||||
- name: install llvm-tools
|
||||
if: matrix.version != '20'
|
||||
run: sudo apt install -y clang-${{ matrix.version }} llvm-${{ matrix.version }}
|
||||
- name: install clang-rt
|
||||
if: matrix.version != '20'
|
||||
run: sudo apt install -y libclang-${{ matrix.version }}-dev
|
||||
- name: compiler installed
|
||||
run: gcc -v; echo; clang -v
|
||||
- name: build afl++
|
||||
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-${{ matrix.version }}; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} all
|
||||
- name: Check llvm passes
|
||||
run: make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-${{ matrix.version }} llvm-build-test || exit 1
|
||||
- name: run tests
|
||||
run: sudo -E ./afl-system-config; make tests
|
||||
|
||||
linux:
|
||||
runs-on: "${{ matrix.os }}"
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-24.04, ubuntu-22.04, ubuntu-24.04-arm]
|
||||
env:
|
||||
AFL_SKIP_CPUFREQ: 1
|
||||
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: update
|
||||
run: sudo apt-get update && sudo apt-get upgrade -y
|
||||
- name: debug
|
||||
run: apt-cache search plugin-dev | grep gcc-; echo; apt-cache search clang-format- | grep clang-format-
|
||||
- name: install packages
|
||||
run: sudo apt-get install -y -m -f build-essential gcc-12 g++-12 git libtool libtool-bin automake flex bison libglib2.0-0 clang-15 llvm-15-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build python3-pip gcc-12-plugin-dev
|
||||
- name: compiler installed
|
||||
run: gcc -v; echo; clang -v
|
||||
- name: install gcc plugin
|
||||
run: sudo apt-get install -y -m -f --install-suggests $(readlink /usr/bin/gcc)-plugin-dev
|
||||
- name: build afl++
|
||||
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-12; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-12 distrib
|
||||
run: export NO_NYX=1; export ASAN_BUILD=1; export LLVM_CONFIG=llvm-config-15; make ASAN_BUILD=1 NO_NYX=1 LLVM_CONFIG=llvm-config-15 distrib
|
||||
- name: run tests
|
||||
run: sudo -E ./afl-system-config; make tests
|
||||
macos:
|
||||
@ -45,7 +117,7 @@ jobs:
|
||||
- name: install
|
||||
run: brew install make gcc llvm
|
||||
# - name: fix install
|
||||
# run: cd /usr/local/bin; ln -s gcc-11 gcc; ln -s g++-11 g++; which gcc; gcc -v
|
||||
# run: cd /usr/local/bin; ln -s gcc-12 gcc; ln -s g++-12 g++; which gcc; gcc -v
|
||||
# - name: build
|
||||
# run: export PATH=/usr/local/Cellar/llvm/*/":$PATH"; export CC=/usr/local/Cellar/llvm/*/bin/clang; export CXX="$CC"++; export LLVM_CONFIG=/usr/local/Cellar/llvm/*/bin/llvm-config; sudo -E ./afl-system-config; gmake ASAN_BUILD=1 afl-fuzz
|
||||
- name: build
|
||||
|
4
.github/workflows/code-format.yml
vendored
4
.github/workflows/code-format.yml
vendored
@ -9,6 +9,10 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
code-format-check:
|
||||
name: Check code format
|
||||
|
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@ -9,6 +9,10 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
|
39
.github/workflows/container.yml
vendored
39
.github/workflows/container.yml
vendored
@ -10,17 +10,21 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-test-amd64:
|
||||
name: Test amd64 image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build amd64
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
tags: aflplusplus:test-amd64
|
||||
@ -35,20 +39,41 @@ jobs:
|
||||
apt-get install -y libcmocka-dev &&
|
||||
make -i tests
|
||||
"
|
||||
build-and-test-arm64:
|
||||
name: Test arm64 image
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build arm64
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
tags: aflplusplus:test-arm64
|
||||
load: true
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
TEST_BUILD=1
|
||||
- name: Test arm64
|
||||
run: >
|
||||
docker run --rm aflplusplus:test-arm64 bash -c "
|
||||
apt-get update &&
|
||||
apt-get install -y libcmocka-dev &&
|
||||
make -i tests
|
||||
"
|
||||
|
||||
push:
|
||||
name: Push amd64 and arm64 images
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build-and-test-amd64
|
||||
- build-and-test-arm64
|
||||
if: ${{ github.event_name == 'push' && github.repository == 'AFLplusplus/AFLplusplus' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
with:
|
||||
platforms: arm64
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to docker.io
|
||||
|
6
.github/workflows/rust_custom_mutator.yml
vendored
6
.github/workflows/rust_custom_mutator.yml
vendored
@ -9,6 +9,10 @@ on:
|
||||
branches:
|
||||
- dev # No need for stable-pull-request, as that equals dev-push
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test Rust Custom Mutator Support
|
||||
@ -18,7 +22,7 @@ jobs:
|
||||
working-directory: custom_mutators/rust
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-20.04]
|
||||
os: [ubuntu-22.04]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Rust Toolchain
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -7,6 +7,7 @@
|
||||
*.so
|
||||
*.swp
|
||||
.DS_Store
|
||||
.format-cache
|
||||
.sync_tmp
|
||||
.test
|
||||
.test2
|
||||
@ -107,10 +108,12 @@ utils/persistent_mode/persistent_demo
|
||||
utils/persistent_mode/persistent_demo_new
|
||||
utils/persistent_mode/persistent_demo_new_compat
|
||||
utils/persistent_mode/test-instr
|
||||
utils/qemu_persistent_hook/mipsel_test
|
||||
utils/qemu_persistent_hook/test
|
||||
utils/replay_record/persistent_demo_replay
|
||||
utils/replay_record/persistent_demo_replay_compat
|
||||
utils/replay_record/persistent_demo_replay_argparse
|
||||
utils/plot_ui/afl-plot-ui
|
||||
vuln_prog
|
||||
argv_fuzz_demo
|
||||
argv_fuzz_persistent_demo
|
||||
argv_fuzz_persistent_demo
|
||||
|
13
Dockerfile
13
Dockerfile
@ -5,7 +5,7 @@
|
||||
# GCC 11 is used instead of 12 because genhtml for afl-cov doesn't like it.
|
||||
#
|
||||
|
||||
FROM ubuntu:22.04 AS aflplusplus
|
||||
FROM ubuntu:24.04 AS aflplusplus
|
||||
LABEL "maintainer"="AFL++ team <afl@aflplus.plus>"
|
||||
LABEL "about"="AFLplusplus container image"
|
||||
|
||||
@ -17,7 +17,7 @@ ENV NO_NYX=1
|
||||
|
||||
### Only change these if you know what you are doing:
|
||||
# Current recommended LLVM version is 16
|
||||
ENV LLVM_VERSION=16
|
||||
ENV LLVM_VERSION=19
|
||||
# GCC 12 is producing compile errors for some targets so we stay at GCC 11
|
||||
ENV GCC_VERSION=11
|
||||
|
||||
@ -32,8 +32,8 @@ RUN apt-get update && apt-get full-upgrade -y && \
|
||||
apt-get install -y --no-install-recommends wget ca-certificates apt-utils && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \
|
||||
wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key
|
||||
#RUN echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg.key] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list && \
|
||||
# wget -qO /etc/apt/keyrings/llvm-snapshot.gpg.key https://apt.llvm.org/llvm-snapshot.gpg.key
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install --no-install-recommends \
|
||||
@ -61,11 +61,12 @@ RUN apt-get update && \
|
||||
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 0 && \
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} 0 && \
|
||||
update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${GCC_VERSION} 0 && \
|
||||
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_VERSION} 0 && \
|
||||
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${LLVM_VERSION} 0
|
||||
|
||||
RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path
|
||||
ENV PATH=$PATH:/etc/cargo/bin
|
||||
#RUN wget -qO- https://sh.rustup.rs | CARGO_HOME=/etc/cargo sh -s -- -y -q --no-modify-path
|
||||
#ENV PATH=$PATH:/etc/cargo/bin
|
||||
|
||||
RUN apt clean -y
|
||||
|
||||
|
134
GNUmakefile
134
GNUmakefile
@ -31,7 +31,7 @@ PROGNAME = afl
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ../config.h | cut -d '"' -f2)
|
||||
|
||||
PROGS = afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
|
||||
SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-cmin.py afl-whatsup afl-addseeds afl-system-config afl-persistent-config afl-cc
|
||||
HEADERS = include/afl-fuzz.h include/afl-mutations.h include/afl-persistent-replay.h include/afl-prealloc.h include/afl-record-compat.h include/alloc-inl.h include/android-ashmem.h include/cmplog.h include/common.h include/config.h include/coverage-32.h include/coverage-64.h include/debug.h include/envs.h include/forkserver.h include/hash.h include/list.h include/sharedmem.h include/snapshot-inl.h include/t1ha.h include/t1ha0_ia32aes_b.h include/t1ha_bits.h include/t1ha_selfcheck.h include/types.h include/xxhash.h
|
||||
MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8)
|
||||
ASAN_OPTIONS=detect_leaks=0
|
||||
@ -41,10 +41,6 @@ ARCH = $(shell uname -m)
|
||||
|
||||
$(info [*] Compiling AFL++ for OS $(SYS) on ARCH $(ARCH))
|
||||
|
||||
ifdef NO_SPLICING
|
||||
override CFLAGS_OPT += -DNO_SPLICING
|
||||
endif
|
||||
|
||||
ifdef NO_UTF
|
||||
override CFLAGS_OPT += -DFANCY_BOXES_NO_UTF
|
||||
endif
|
||||
@ -65,20 +61,31 @@ ifdef MSAN_BUILD
|
||||
override CFLAGS += -fsanitize=memory -fno-omit-frame-pointer
|
||||
override LDFLAGS += -fsanitize=memory
|
||||
endif
|
||||
ifdef NO_SPLICING
|
||||
$(info The NO_SPLICING parameter is deprecated)
|
||||
endif
|
||||
|
||||
|
||||
ifdef CODE_COVERAGE
|
||||
override CFLAGS += -D__AFL_CODE_COVERAGE=1
|
||||
endif
|
||||
|
||||
IS_IOS:=$(findstring ios, $(shell $(CC) --version 2>/dev/null))
|
||||
ifdef IS_IOS
|
||||
override CFLAGS += -DTARGET_OS_IPHONE -DTARGET_OS_IOS -isysroot $(IOS_SDK_PATH)
|
||||
endif
|
||||
|
||||
ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
ifndef ASAN_BUILD
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=full
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto=thin
|
||||
else
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
CFLAGS_FLTO ?= -flto
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -101,17 +108,19 @@ else
|
||||
SPECIAL_PERFORMANCE :=
|
||||
endif
|
||||
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
#ifeq "$(HAVE_MARCHNATIVE)" "1"
|
||||
# SPECIAL_PERFORMANCE += -march=native
|
||||
#endif
|
||||
#ifndef DEBUG
|
||||
# override CFLAGS_OPT += -D_FORTIFY_SOURCE=1
|
||||
#endif
|
||||
else
|
||||
# On some odd MacOS system configurations, the Xcode sdk path is not set correctly
|
||||
SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib
|
||||
override LDFLAGS += $(SDK_LD)
|
||||
ifndef IS_IOS
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
#ifeq "$(HAVE_MARCHNATIVE)" "1"
|
||||
# SPECIAL_PERFORMANCE += -march=native
|
||||
#endif
|
||||
#ifndef DEBUG
|
||||
# override CFLAGS_OPT += -D_FORTIFY_SOURCE=1
|
||||
#endif
|
||||
else
|
||||
# On some odd MacOS system configurations, the Xcode sdk path is not set correctly
|
||||
SDK_LD = -L$(shell xcrun --show-sdk-path)/usr/lib
|
||||
override LDFLAGS += $(SDK_LD)
|
||||
endif
|
||||
endif
|
||||
|
||||
COMPILER_TYPE=$(shell $(CC) --version|grep "Free Software Foundation")
|
||||
@ -246,17 +255,6 @@ ifeq "$(PYTHON_INCLUDE)" ""
|
||||
endif
|
||||
endif
|
||||
|
||||
# Old Ubuntu and others dont have python/python2-config so we hardcode 2.7
|
||||
ifeq "$(PYTHON_INCLUDE)" ""
|
||||
ifneq "$(shell command -v python2.7 2>/dev/null)" ""
|
||||
ifneq "$(shell command -v python2.7-config 2>/dev/null)" ""
|
||||
PYTHON_INCLUDE := $(shell python2.7-config --includes)
|
||||
PYTHON_LIB := $(shell python2.7-config --ldflags)
|
||||
PYTHON_VERSION := $(strip $(shell python2.7 --version 2>&1))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef SOURCE_DATE_EPOCH
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
|
||||
else
|
||||
@ -282,7 +280,7 @@ ifneq "$(findstring OpenBSD, $(SYS))" ""
|
||||
override LDFLAGS += -lpthread -lm
|
||||
endif
|
||||
|
||||
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h
|
||||
COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h include/afl-fuzz.h include/hash.h include/sharedmem.h include/forkserver.h include/common.h include/list.h
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test $(PYTHON_INCLUDE) $(LDFLAGS) $(PYTHON_LIB) 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
PYTHON_OK=1
|
||||
@ -306,8 +304,8 @@ ifeq "$(shell command -v svn >/dev/null && svn proplist . 2>/dev/null && echo 1
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() { return 0;}' | $(CC) $(CFLAGS) -fsanitize=address -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD
|
||||
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer
|
||||
ASAN_CFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -DASAN_BUILD -fno-lto
|
||||
ASAN_LDFLAGS=-fsanitize=address -fstack-protector-all -fno-omit-frame-pointer -fno-lto
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
|
||||
@ -347,6 +345,11 @@ llvm:
|
||||
-$(MAKE) -j$(nproc) -f GNUmakefile.llvm
|
||||
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
|
||||
|
||||
llvm-build-test:
|
||||
$(MAKE) -j$(nproc) -f GNUmakefile.llvm
|
||||
@test -e afl-cc || { echo "[-] Compiling afl-cc failed. You seem not to have a working compiler." ; exit 1; }
|
||||
|
||||
|
||||
.PHONY: gcc_plugin
|
||||
gcc_plugin:
|
||||
ifneq "$(SYS)" "Darwin"
|
||||
@ -408,7 +411,6 @@ help:
|
||||
@echo PROFILING - compile afl-fuzz with profiling information
|
||||
@echo INTROSPECTION - compile afl-fuzz with mutation introspection
|
||||
@echo NO_PYTHON - disable python support
|
||||
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
@echo "NO_UTF - do not use UTF-8 for line rendering in status screen (fallback to G1 box drawing, of vanilla AFL)"
|
||||
@echo NO_NYX - disable building nyx mode dependencies
|
||||
@echo "NO_CORESIGHT - disable building coresight (arm64 only)"
|
||||
@ -466,32 +468,47 @@ endif
|
||||
ready:
|
||||
@echo "[+] Everything seems to be working, ready to compile. ($(shell $(CC) --version 2>&1|head -n 1))"
|
||||
|
||||
src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
|
||||
src/afl-performance.o: $(COMM_HDR) src/afl-performance.c
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o
|
||||
|
||||
src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h
|
||||
src/afl-common.o: $(COMM_HDR) src/afl-common.c include/envs.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-common.c -o src/afl-common.o
|
||||
|
||||
src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
|
||||
src/afl-forkserver.o: $(COMM_HDR) src/afl-forkserver.c
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-forkserver.c -o src/afl-forkserver.o
|
||||
|
||||
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
|
||||
src/afl-sharedmem.o: $(COMM_HDR) src/afl-sharedmem.c include/android-ashmem.h include/cmplog.h
|
||||
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
|
||||
|
||||
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86
|
||||
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o include/cmplog.h include/envs.h | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
afl-showmap: src/afl-showmap.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS)
|
||||
afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/afl-fuzz-python.o src/afl-fuzz-mutators.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/afl-fuzz-python.o src/afl-fuzz-mutators.o -o $@ $(PYFLAGS) $(LDFLAGS)
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS)
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86
|
||||
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-common.o -o $@ $(LDFLAGS)
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
.PHONY: document
|
||||
document: afl-fuzz-document
|
||||
@ -499,6 +516,9 @@ document: afl-fuzz-document
|
||||
# document all mutations and only do one run (use with only one input file!)
|
||||
afl-fuzz-document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-performance.o | test_x86
|
||||
$(CC) -D_DEBUG=\"1\" -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.c src/afl-performance.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS)
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o
|
||||
@ -506,20 +526,29 @@ test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittes
|
||||
unit_maybe_alloc: test/unittests/unit_maybe_alloc.o
|
||||
@$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_maybe_alloc
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
|
||||
@$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o
|
||||
|
||||
unit_hash: test/unittests/unit_hash.o src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
@$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_hash
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
|
||||
@$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o
|
||||
|
||||
unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
@$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_rand
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o
|
||||
@ -527,6 +556,9 @@ test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list
|
||||
unit_list: test/unittests/unit_list.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_list
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES)
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o
|
||||
@ -534,6 +566,9 @@ test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unitte
|
||||
unit_preallocable: test/unittests/unit_preallocable.o
|
||||
@$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka
|
||||
./test/unittests/unit_preallocable
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
.PHONY: unit_clean
|
||||
unit_clean:
|
||||
@ -645,6 +680,7 @@ deepclean: clean
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
rm -rf qemu_mode/qemuafl
|
||||
rm -rf nyx_mode/libnyx nyx_mode/packer nyx_mode/QEMU-Nyx
|
||||
rm -rf .format-cache
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
git checkout coresight_mode/coresight-trace
|
||||
git checkout unicorn_mode/unicornafl
|
||||
|
@ -148,7 +148,7 @@ afl-common.o: ./src/afl-common.c
|
||||
$(PASSES): instrumentation/afl-gcc-common.h
|
||||
|
||||
./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@
|
||||
$(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ $(LDFLAGS)
|
||||
ln -sf afl-cc afl-gcc-fast
|
||||
ln -sf afl-cc afl-g++-fast
|
||||
ln -sf afl-cc.8 afl-gcc-fast.8
|
||||
|
104
GNUmakefile.llvm
104
GNUmakefile.llvm
@ -28,12 +28,12 @@ MAN_PATH ?= $(PREFIX)/share/man/man8
|
||||
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
|
||||
VERSION = $(shell grep '^ *$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
|
||||
override LLVM_TOO_NEW_DEFAULT := 18
|
||||
override LLVM_TOO_OLD_DEFAULT := 13
|
||||
override LLVM_TOO_NEW_DEFAULT := 21
|
||||
override LLVM_TOO_OLD_DEFAULT := 14
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
|
||||
@ -69,16 +69,16 @@ endif
|
||||
|
||||
LLVM_STDCXX := gnu++11
|
||||
LLVM_LTO := 0
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.' && echo 1 || echo 0)
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[2-9]\.' && echo 1 || echo 0)
|
||||
# Uncomment to see the values assigned above
|
||||
# $(foreach var,LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
|
||||
# $(foreach var,_CLANG_VERSIONS_TO_TEST LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
|
||||
|
||||
ifeq "$(LLVMVER)" ""
|
||||
$(warning [!] llvm_mode needs llvm-config, which was not found. Set LLVM_CONFIG to its path and retry.)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_UNSUPPORTED)" "1"
|
||||
$(error llvm_mode only supports llvm from version 3.8 onwards)
|
||||
$(error llvm_mode only supports llvm from version 3.8 onwards - or your version is too new. Upgrade AFL++ if possible or downgrade LLVM.)
|
||||
endif
|
||||
|
||||
ifeq "$(LLVM_TOO_NEW)" "1"
|
||||
@ -237,20 +237,21 @@ ifeq "$(LLVM_LTO)" "1"
|
||||
ifeq "$(AFL_REAL_LD)" ""
|
||||
ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
|
||||
AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
|
||||
else ifneq "$(shell command -v ld.lld 2>/dev/null)" ""
|
||||
AFL_REAL_LD = $(shell command -v ld.lld)
|
||||
TMP_LDLDD_VERSION = $(shell $(AFL_REAL_LD) --version | awk '{ print $$2 }')
|
||||
ifeq "$(LLVMVER)" "$(TMP_LDLDD_VERSION)"
|
||||
$(warning ld.lld found in a weird location ($(AFL_REAL_LD)), but its the same version as LLVM so we will allow it)
|
||||
else
|
||||
ifneq "$(shell command -v ld.lld 2>/dev/null)" ""
|
||||
AFL_REAL_LD = $(shell command -v ld.lld)
|
||||
TMP_LDLDD_VERSION = $(shell $(AFL_REAL_LD) --version | sed -E -ne '/^.*LLD\ ([12]?[0-9]\.[0-9]\.[0-9]).*/s//\1/p')
|
||||
ifeq "$(LLVMVER)" "$(TMP_LDLDD_VERSION)"
|
||||
$(warning ld.lld found in a weird location ($(AFL_REAL_LD)), but its the same version as LLVM so we will allow it)
|
||||
else
|
||||
$(warning ld.lld found in a weird location ($(AFL_REAL_LD)) and its of a different version than LLMV ($(TMP_LDLDD_VERSION) vs. $(LLVMVER)) - cannot enable LTO mode)
|
||||
AFL_REAL_LD=
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
else
|
||||
$(warning ld.lld found in a weird location ($(AFL_REAL_LD)) and its of a different version than LLMV ($(TMP_LDLDD_VERSION) vs. $(LLVMVER)) - cannot enable LTO mode)
|
||||
AFL_REAL_LD=
|
||||
$(warning ld.lld not found, cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
undefine TMP_LDLDD_VERSION
|
||||
else
|
||||
$(warning ld.lld not found, cannot enable LTO mode)
|
||||
LLVM_LTO = 0
|
||||
endif
|
||||
endif
|
||||
else
|
||||
@ -272,11 +273,7 @@ ifeq "$(LLVM_LTO)" "1"
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fdebug-prefix-map=$(CURDIR)=llvm_mode -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
|
||||
AFL_CLANG_DEBUG_PREFIX = -fdebug-prefix-map="$(CURDIR)=llvm_mode"
|
||||
else
|
||||
AFL_CLANG_DEBUG_PREFIX =
|
||||
endif
|
||||
IS_IOS := $(findstring ios, $(shell $(CC) --version 2>/dev/null))
|
||||
|
||||
CFLAGS ?= -O3 -funroll-loops -fPIC
|
||||
# -D_FORTIFY_SOURCE=1
|
||||
@ -288,11 +285,15 @@ CFLAGS_SAFE := -Wall -g -Wno-cast-qual -Wno-variadic-macros -Wno-pointer-sig
|
||||
-DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" \
|
||||
-DAFL_CLANG_LDPATH=\"$(AFL_CLANG_LDPATH)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
|
||||
-DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) \
|
||||
-Wno-unused-function $(AFL_CLANG_DEBUG_PREFIX)
|
||||
-Wno-unused-function
|
||||
ifndef LLVM_DEBUG
|
||||
CFLAGS_SAFE += -Wno-deprecated
|
||||
endif
|
||||
|
||||
ifdef IOS_SDK_PATH
|
||||
override CFLAGS_SAFE += -isysroot $(IOS_SDK_PATH)
|
||||
endif
|
||||
|
||||
ifdef CODE_COVERAGE
|
||||
override CFLAGS_SAFE += -D__AFL_CODE_COVERAGE=1
|
||||
override LDFLAGS += -ldl
|
||||
@ -310,6 +311,10 @@ override CXXFLAGS += -Wall -g -I ./include/ \
|
||||
-DVERSION=\"$(VERSION)\" -Wno-variadic-macros -Wno-deprecated-copy-with-dtor \
|
||||
-DLLVM_MINOR=$(LLVM_MINOR) -DLLVM_MAJOR=$(LLVM_MAJOR)
|
||||
|
||||
ifdef IOS_SDK_PATH
|
||||
override CXXFLAGS += -isysroot $(IOS_SDK_PATH)
|
||||
endif
|
||||
|
||||
ifneq "$(shell $(LLVM_CONFIG) --includedir) 2> /dev/null" ""
|
||||
CLANG_CFL = -I$(shell $(LLVM_CONFIG) --includedir)
|
||||
endif
|
||||
@ -335,7 +340,7 @@ else
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
CLANG_LFL += $$($(LLVM_CONFIG) --libdir)/libLLVM.so
|
||||
CLANG_LFL += $(LLVM_LIBDIR)/libLLVM.so
|
||||
CLANG_CPPFL += -mno-retpoline
|
||||
CFLAGS += -mno-retpoline
|
||||
# Needed for unwind symbols
|
||||
@ -356,7 +361,7 @@ ifeq "$(TEST_MMAP)" "1"
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./cmplog-switches-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./SanitizerCoverageLTO.so ./injection-pass.so
|
||||
|
||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||
@ -431,29 +436,44 @@ ifeq "$(LLVM_LTO)" "1"
|
||||
@ln -sf afl-cc ./afl-lto++
|
||||
endif
|
||||
endif
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) $$($(LLVM_CONFIG) --cxxflags) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) $$($(LLVM_CONFIG) --cxxflags) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@
|
||||
|
||||
./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
ifeq "$(LLVM_MIN_4_0_1)" "0"
|
||||
$(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER))
|
||||
endif
|
||||
$(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
ifeq "$(LLVM_13_OK)" "1"
|
||||
-$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
endif
|
||||
|
||||
./afl-llvm-lto-instrumentlist.so: instrumentation/afl-llvm-lto-instrumentlist.so.cc instrumentation/afl-llvm-common.o
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
endif
|
||||
|
||||
./afl-ld-lto: src/afl-ld-lto.c
|
||||
ifeq "$(LLVM_LTO)" "1"
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LDFLAGS)
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
endif
|
||||
|
||||
./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc instrumentation/afl-llvm-common.o
|
||||
@ -462,31 +482,58 @@ ifeq "$(LLVM_LTO)" "1"
|
||||
$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o
|
||||
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
|
||||
@$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
endif
|
||||
|
||||
# laf
|
||||
./split-switches-pass.so: instrumentation/split-switches-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
./compare-transform-pass.so: instrumentation/compare-transform-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
./split-compares-pass.so: instrumentation/split-compares-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
# /laf
|
||||
|
||||
./cmplog-routines-pass.so: instrumentation/cmplog-routines-pass.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
./cmplog-switches-pass.so: instrumentation/cmplog-switches-pass.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
./injection-pass.so: instrumentation/injection-pass.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
.PHONY: document
|
||||
document:
|
||||
@ -509,6 +556,9 @@ document:
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO AFL_LLVM_ALLOWLIST AFL_LLVM_DENYLIST; ASAN_OPTIONS=detect_leaks=0 AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_ALL=1 ./afl-cc $(CFLAGS) $(CPPFLAGS) ./test-instr.c -o test-instr $(LDFLAGS)
|
||||
ifdef IS_IOS
|
||||
@ldid -Sentitlements.plist test-instr && echo "[+] Signed test-instr" || echo "[-] Failed to sign test-instr"
|
||||
endif
|
||||
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
|
||||
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
|
||||
@rm -f test-instr
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/main/static/aflpp_bg.svg" alt="AFL++ logo" width="250" height="250">
|
||||
|
||||
Release version: [4.30c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
Release version: [4.32c](https://github.com/AFLplusplus/AFLplusplus/releases)
|
||||
|
||||
GitHub version: 4.31a
|
||||
GitHub version: 4.33a
|
||||
|
||||
Repository:
|
||||
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
|
||||
@ -16,7 +16,6 @@ AFL++ is maintained by:
|
||||
* Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
* Heiko "hexcoder-" Eissfeldt <heiko.eissfeldt@hexco.de>
|
||||
* frida_mode is maintained by @Worksbutnottested
|
||||
* Documentation: Jana Aydinbas <jana.aydinbas@gmail.com>
|
||||
|
||||
Originally developed by Michal "lcamtuf" Zalewski.
|
||||
|
||||
@ -230,6 +229,8 @@ Thank you! (For people sending pull requests - please add yourself to this list
|
||||
Ruben ten Hove Joey Jiao
|
||||
fuzzah @intrigus-lgtm
|
||||
Yaakov Saxon Sergej Schumilo
|
||||
Ziqiao Kong Ryan Berger
|
||||
Sangjun Park Scott Guest
|
||||
```
|
||||
|
||||
</details>
|
||||
@ -258,3 +259,5 @@ presented at WOOT'20:
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
[](https://deepwiki.com/AFLplusplus/AFLplusplus)
|
||||
|
1
TODO.md
1
TODO.md
@ -2,6 +2,7 @@
|
||||
|
||||
## Must
|
||||
|
||||
- afl_fsrv_deinit cmplog
|
||||
- ijon support?
|
||||
- check for null ptr for xml/curl/g_ string transform functions
|
||||
- hardened_usercopy=0 page_alloc.shuffle=0
|
||||
|
13
afl-cmin
13
afl-cmin
@ -1,12 +1,19 @@
|
||||
#!/usr/bin/env sh
|
||||
THISPATH=`dirname ${0}`
|
||||
|
||||
# call afl-cmin.py if it can be executed successfully.
|
||||
if $THISPATH/afl-cmin.py --help > /dev/null 2>&1; then
|
||||
exec $THISPATH/afl-cmin.py "$@"
|
||||
fi
|
||||
|
||||
SYS=$(uname -s)
|
||||
test "$SYS" = "Darwin" && {
|
||||
echo Error: afl-cmin does not work on Apple currently. please use afl-cmin.bash instead.
|
||||
exit 1
|
||||
}
|
||||
|
||||
export AFL_QUIET=1
|
||||
export ASAN_OPTIONS=detect_leaks=0
|
||||
THISPATH=`dirname ${0}`
|
||||
export PATH="${THISPATH}:$PATH"
|
||||
awk -f - -- ${@+"$@"} <<'EOF'
|
||||
#!/usr/bin/awk -f
|
||||
@ -331,7 +338,7 @@ BEGIN {
|
||||
}
|
||||
|
||||
if (0 == system ( "grep -aq AFL_DUMP_MAP_SIZE " target_bin )) {
|
||||
echo "[!] Trying to obtain the map size of the target ..."
|
||||
print "[!] Trying to obtain the map size of the target ..."
|
||||
get_map_size = "AFL_DUMP_MAP_SIZE=1 " target_bin
|
||||
get_map_size | getline mapsize
|
||||
close(get_map_size)
|
||||
@ -432,7 +439,7 @@ BEGIN {
|
||||
} else {
|
||||
stat_format = "-f '%z %N'" # *BSD, MacOS
|
||||
}
|
||||
cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r) | grep -Ev '^0'"
|
||||
cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o \\( -type f -a ! -name \"cmdline\" -a ! -name \"fastresume.bin\" -a ! -name \"fuzz_bitmap\" -a ! -name \"fuzzer_setup\" -a ! -name \"fuzzer_stats\" -a ! -name \"plot_data\" -a ! -name \"target_hash\" \\) -exec stat "stat_format" \\{\\} + | sort -k1n -k2r) | grep -Ev '^0'"
|
||||
#cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r"
|
||||
#cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r"
|
||||
#cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r"
|
||||
|
760
afl-cmin.py
Executable file
760
afl-cmin.py
Executable file
@ -0,0 +1,760 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2016-2025 Google Inc.
|
||||
# Copyright 2025 AFLplusplus Project. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import argparse
|
||||
import array
|
||||
import base64
|
||||
import collections
|
||||
import glob
|
||||
import hashlib
|
||||
import itertools
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# https://more-itertools.readthedocs.io/en/stable/_modules/more_itertools/recipes.html#batched
|
||||
from sys import hexversion
|
||||
|
||||
def _batched(iterable, n, *, strict=False):
|
||||
"""Batch data into tuples of length *n*. If the number of items in
|
||||
*iterable* is not divisible by *n*:
|
||||
* The last batch will be shorter if *strict* is ``False``.
|
||||
* :exc:`ValueError` will be raised if *strict* is ``True``.
|
||||
|
||||
>>> list(batched('ABCDEFG', 3))
|
||||
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]
|
||||
|
||||
On Python 3.13 and above, this is an alias for :func:`itertools.batched`.
|
||||
"""
|
||||
if n < 1:
|
||||
raise ValueError('n must be at least one')
|
||||
iterator = iter(iterable)
|
||||
while batch := tuple(itertools.islice(iterator, n)):
|
||||
if strict and len(batch) != n:
|
||||
raise ValueError('batched(): incomplete batch')
|
||||
yield batch
|
||||
|
||||
|
||||
if hexversion >= 0x30D00A2: # pragma: no cover
|
||||
from itertools import batched as itertools_batched
|
||||
def batched(iterable, n, *, strict=False):
|
||||
return itertools_batched(iterable, n, strict=strict)
|
||||
else:
|
||||
batched = _batched
|
||||
|
||||
batched.__doc__ = _batched.__doc__
|
||||
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
except ImportError:
|
||||
print('Hint: install python module "tqdm" to show progress bar')
|
||||
|
||||
class tqdm:
|
||||
|
||||
def __init__(self, data=None, *args, **argd):
|
||||
self.data = data
|
||||
|
||||
def __iter__(self):
|
||||
yield from self.data
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
def update(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
cpu_count = multiprocessing.cpu_count()
|
||||
group = parser.add_argument_group("Required parameters")
|
||||
group.add_argument(
|
||||
"-i",
|
||||
dest="input",
|
||||
action="append",
|
||||
metavar="dir",
|
||||
required=True,
|
||||
help="input directory with the starting corpus",
|
||||
)
|
||||
group.add_argument(
|
||||
"-o",
|
||||
dest="output",
|
||||
metavar="dir",
|
||||
required=True,
|
||||
help="output directory for minimized files",
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Execution control settings")
|
||||
group.add_argument(
|
||||
"-f",
|
||||
dest="stdin_file",
|
||||
metavar="file",
|
||||
help="location read by the fuzzed program (stdin)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-m",
|
||||
dest="memory_limit",
|
||||
default="none",
|
||||
metavar="megs",
|
||||
type=lambda x: x if x == "none" else int(x),
|
||||
help="memory limit for child process (default: %(default)s)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-t",
|
||||
dest="time_limit",
|
||||
default=5000,
|
||||
metavar="msec",
|
||||
type=lambda x: x if x == "none" else int(x),
|
||||
help="timeout for each run (default: %(default)s)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-O",
|
||||
dest="frida_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use binary-only instrumentation (FRIDA mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-Q",
|
||||
dest="qemu_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use binary-only instrumentation (QEMU mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-U",
|
||||
dest="unicorn_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="use unicorn-based instrumentation (Unicorn mode)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-X", dest="nyx_mode", action="store_true", default=False, help="use Nyx mode"
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Minimization settings")
|
||||
group.add_argument(
|
||||
"--crash-dir",
|
||||
dest="crash_dir",
|
||||
metavar="dir",
|
||||
default=None,
|
||||
help="move crashes to a separate dir, always deduplicated",
|
||||
)
|
||||
group.add_argument(
|
||||
"-A",
|
||||
dest="allow_any",
|
||||
action="store_true",
|
||||
help="allow crashes and timeouts (not recommended)",
|
||||
)
|
||||
group.add_argument(
|
||||
"-C",
|
||||
dest="crash_only",
|
||||
action="store_true",
|
||||
help="keep crashing inputs, reject everything else",
|
||||
)
|
||||
group.add_argument(
|
||||
"-e",
|
||||
dest="edge_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="solve for edge coverage only, ignore hit counts",
|
||||
)
|
||||
|
||||
group = parser.add_argument_group("Misc")
|
||||
group.add_argument(
|
||||
"-T",
|
||||
dest="workers",
|
||||
type=lambda x: cpu_count if x == "all" else int(x),
|
||||
default=1,
|
||||
help="number of concurrent worker (default: %(default)d)",
|
||||
)
|
||||
group.add_argument(
|
||||
"--as_queue",
|
||||
action="store_true",
|
||||
help='output file name like "id:000000,hash:value"',
|
||||
)
|
||||
group.add_argument(
|
||||
"--no-dedup", action="store_true", help="skip deduplication step for corpus files"
|
||||
)
|
||||
group.add_argument("--debug", action="store_true")
|
||||
|
||||
parser.add_argument("exe", metavar="/path/to/target_app")
|
||||
parser.add_argument("args", nargs="*")
|
||||
|
||||
args = parser.parse_args()
|
||||
logger = None
|
||||
afl_showmap_bin = None
|
||||
tuple_index_type_code = "I"
|
||||
file_index_type_code = None
|
||||
|
||||
|
||||
def init():
|
||||
global logger
|
||||
log_level = logging.DEBUG if args.debug else logging.INFO
|
||||
logging.basicConfig(
|
||||
level=log_level, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if args.stdin_file and args.workers > 1:
|
||||
logger.error("-f is only supported with one worker (-T 1)")
|
||||
sys.exit(1)
|
||||
|
||||
if args.memory_limit != "none" and args.memory_limit < 5:
|
||||
logger.error("dangerously low memory limit")
|
||||
sys.exit(1)
|
||||
|
||||
if args.time_limit != "none" and args.time_limit < 10:
|
||||
logger.error("dangerously low timeout")
|
||||
sys.exit(1)
|
||||
|
||||
if not os.path.isfile(args.exe):
|
||||
logger.error('binary "%s" not found or not regular file', args.exe)
|
||||
sys.exit(1)
|
||||
|
||||
if not os.environ.get("AFL_SKIP_BIN_CHECK") and not any(
|
||||
[args.qemu_mode, args.frida_mode, args.unicorn_mode, args.nyx_mode]
|
||||
):
|
||||
if b"__AFL_SHM_ID" not in open(args.exe, "rb").read():
|
||||
logger.error("binary '%s' doesn't appear to be instrumented", args.exe)
|
||||
sys.exit(1)
|
||||
|
||||
for dn in args.input:
|
||||
if not os.path.isdir(dn) and not glob.glob(dn):
|
||||
logger.error('directory "%s" not found', dn)
|
||||
sys.exit(1)
|
||||
|
||||
global afl_showmap_bin
|
||||
searches = [
|
||||
None,
|
||||
os.path.dirname(__file__),
|
||||
os.getcwd(),
|
||||
]
|
||||
if os.environ.get("AFL_PATH"):
|
||||
searches.append(os.environ["AFL_PATH"])
|
||||
|
||||
for search in searches:
|
||||
afl_showmap_bin = shutil.which("afl-showmap", path=search)
|
||||
if afl_showmap_bin:
|
||||
break
|
||||
if not afl_showmap_bin:
|
||||
logger.fatal("cannot find afl-showmap, please set AFL_PATH")
|
||||
sys.exit(1)
|
||||
|
||||
trace_dir = os.path.join(args.output, ".traces")
|
||||
shutil.rmtree(trace_dir, ignore_errors=True)
|
||||
try:
|
||||
os.rmdir(args.output)
|
||||
except OSError:
|
||||
pass
|
||||
if os.path.exists(args.output):
|
||||
logger.error(
|
||||
'directory "%s" exists and is not empty - delete it first', args.output
|
||||
)
|
||||
sys.exit(1)
|
||||
if args.crash_dir and not os.path.exists(args.crash_dir):
|
||||
os.makedirs(args.crash_dir)
|
||||
os.makedirs(trace_dir)
|
||||
|
||||
logger.info("use %d workers (-T)", args.workers)
|
||||
|
||||
|
||||
def detect_type_code(size):
|
||||
for type_code in ["B", "H", "I", "L", "Q"]:
|
||||
if 256 ** array.array(type_code).itemsize > size:
|
||||
return type_code
|
||||
|
||||
|
||||
def afl_showmap(input_path=None, batch=None, afl_map_size=None, first=False):
|
||||
assert input_path or batch
|
||||
# yapf: disable
|
||||
cmd = [
|
||||
afl_showmap_bin,
|
||||
'-m', str(args.memory_limit),
|
||||
'-t', str(args.time_limit),
|
||||
'-Z', # cmin mode
|
||||
]
|
||||
# yapf: enable
|
||||
found_atat = False
|
||||
for arg in args.args:
|
||||
if "@@" in arg:
|
||||
found_atat = True
|
||||
|
||||
if args.stdin_file:
|
||||
assert args.workers == 1
|
||||
input_from_file = True
|
||||
stdin_file = args.stdin_file
|
||||
cmd += ["-H", stdin_file]
|
||||
elif found_atat:
|
||||
input_from_file = True
|
||||
stdin_file = os.path.join(args.output, f".input.{os.getpid()}")
|
||||
cmd += ["-H", stdin_file]
|
||||
else:
|
||||
input_from_file = False
|
||||
|
||||
if batch:
|
||||
input_from_file = True
|
||||
filelist = os.path.join(args.output, f".filelist.{os.getpid()}")
|
||||
with open(filelist, "w") as f:
|
||||
for _, path in batch:
|
||||
f.write(path + "\n")
|
||||
cmd += ["-I", filelist]
|
||||
output_path = os.path.join(args.output, f".showmap.{os.getpid()}")
|
||||
cmd += ["-o", output_path]
|
||||
else:
|
||||
if input_from_file:
|
||||
shutil.copy(input_path, stdin_file)
|
||||
cmd += ["-o", "-"]
|
||||
|
||||
if args.frida_mode:
|
||||
cmd += ["-O"]
|
||||
if args.qemu_mode:
|
||||
cmd += ["-Q"]
|
||||
if args.unicorn_mode:
|
||||
cmd += ["-U"]
|
||||
if args.nyx_mode:
|
||||
cmd += ["-X"]
|
||||
if args.edge_mode:
|
||||
cmd += ["-e"]
|
||||
cmd += ["--", args.exe] + args.args
|
||||
|
||||
env = os.environ.copy()
|
||||
env["AFL_QUIET"] = "1"
|
||||
env["ASAN_OPTIONS"] = "detect_leaks=0"
|
||||
if first:
|
||||
logger.debug("run command line: %s", subprocess.list2cmdline(cmd))
|
||||
env["AFL_CMIN_ALLOW_ANY"] = "1"
|
||||
if afl_map_size:
|
||||
env["AFL_MAP_SIZE"] = str(afl_map_size)
|
||||
if args.crash_only:
|
||||
env["AFL_CMIN_CRASHES_ONLY"] = "1"
|
||||
if args.allow_any:
|
||||
env["AFL_CMIN_ALLOW_ANY"] = "1"
|
||||
|
||||
if input_from_file:
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env, bufsize=1048576)
|
||||
else:
|
||||
p = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=open(input_path, "rb"),
|
||||
stdout=subprocess.PIPE,
|
||||
env=env,
|
||||
bufsize=1048576,
|
||||
)
|
||||
out = p.stdout.read()
|
||||
p.wait()
|
||||
|
||||
if batch:
|
||||
result = []
|
||||
for idx, input_path in batch:
|
||||
basename = os.path.basename(input_path)
|
||||
values = []
|
||||
try:
|
||||
trace_file = os.path.join(output_path, basename)
|
||||
with open(trace_file, "r") as f:
|
||||
values = list(map(int, f))
|
||||
crashed = len(values) == 0
|
||||
os.unlink(trace_file)
|
||||
except FileNotFoundError:
|
||||
a = None
|
||||
crashed = True
|
||||
values = [(t // 1000) * 9 + t % 1000 for t in values]
|
||||
a = array.array(tuple_index_type_code, values)
|
||||
result.append((idx, a, crashed))
|
||||
os.unlink(filelist)
|
||||
os.rmdir(output_path)
|
||||
return result
|
||||
else:
|
||||
values = []
|
||||
for line in out.split():
|
||||
if not line.isdigit():
|
||||
continue
|
||||
values.append(int(line))
|
||||
values = [(t // 1000) * 9 + t % 1000 for t in values]
|
||||
a = array.array(tuple_index_type_code, values)
|
||||
crashed = p.returncode in [2, 3]
|
||||
if input_from_file and stdin_file != args.stdin_file:
|
||||
os.unlink(stdin_file)
|
||||
return a, crashed
|
||||
|
||||
|
||||
class JobDispatcher(multiprocessing.Process):
|
||||
|
||||
def __init__(self, job_queue, jobs):
|
||||
super().__init__()
|
||||
self.job_queue = job_queue
|
||||
self.jobs = jobs
|
||||
|
||||
def run(self):
|
||||
for job in self.jobs:
|
||||
self.job_queue.put(job)
|
||||
self.job_queue.close()
|
||||
|
||||
|
||||
class Worker(multiprocessing.Process):
|
||||
|
||||
def __init__(self, idx, afl_map_size, q_in, p_out, r_out):
|
||||
super().__init__()
|
||||
self.idx = idx
|
||||
self.afl_map_size = afl_map_size
|
||||
self.q_in = q_in
|
||||
self.p_out = p_out
|
||||
self.r_out = r_out
|
||||
|
||||
def run(self):
|
||||
map_size = self.afl_map_size or 65536
|
||||
max_tuple = map_size * 9
|
||||
max_file_index = 256 ** array.array(file_index_type_code).itemsize - 1
|
||||
m = array.array(file_index_type_code, [max_file_index] * max_tuple)
|
||||
counter = collections.Counter()
|
||||
crashes = []
|
||||
|
||||
pack_name = os.path.join(args.output, ".traces", f"{self.idx}.pack")
|
||||
pack_pos = 0
|
||||
with open(pack_name, "wb") as trace_pack:
|
||||
while True:
|
||||
batch = self.q_in.get()
|
||||
if batch is None:
|
||||
break
|
||||
|
||||
for idx, r, crash in afl_showmap(
|
||||
batch=batch, afl_map_size=self.afl_map_size
|
||||
):
|
||||
counter.update(r)
|
||||
|
||||
used = False
|
||||
|
||||
if crash:
|
||||
crashes.append(idx)
|
||||
|
||||
# If we aren't saving crashes to a separate dir, handle them
|
||||
# the same as other inputs. However, unless AFL_CMIN_ALLOW_ANY=1,
|
||||
# afl_showmap will not return any coverage for crashes so they will
|
||||
# never be retained.
|
||||
if not crash or not args.crash_dir:
|
||||
for t in r:
|
||||
if idx < m[t]:
|
||||
m[t] = idx
|
||||
used = True
|
||||
|
||||
if used:
|
||||
tuple_count = len(r)
|
||||
r.tofile(trace_pack)
|
||||
self.p_out.put((idx, self.idx, pack_pos, tuple_count))
|
||||
pack_pos += tuple_count * r.itemsize
|
||||
else:
|
||||
self.p_out.put(None)
|
||||
|
||||
self.r_out.put((self.idx, m, counter, crashes))
|
||||
|
||||
|
||||
class CombineTraceWorker(multiprocessing.Process):
|
||||
|
||||
def __init__(self, pack_name, jobs, r_out):
|
||||
super().__init__()
|
||||
self.pack_name = pack_name
|
||||
self.jobs = jobs
|
||||
self.r_out = r_out
|
||||
|
||||
def run(self):
|
||||
already_have = set()
|
||||
with open(self.pack_name, "rb") as f:
|
||||
for pos, tuple_count in self.jobs:
|
||||
f.seek(pos)
|
||||
result = array.array(tuple_index_type_code)
|
||||
result.fromfile(f, tuple_count)
|
||||
already_have.update(result)
|
||||
self.r_out.put(already_have)
|
||||
|
||||
|
||||
def hash_file(path):
|
||||
m = hashlib.sha1()
|
||||
with open(path, "rb") as f:
|
||||
m.update(f.read())
|
||||
return m.digest()
|
||||
|
||||
|
||||
def dedup(files):
|
||||
with multiprocessing.Pool(args.workers) as pool:
|
||||
seen_hash = set()
|
||||
result = []
|
||||
hash_list = []
|
||||
# use large chunksize to reduce multiprocessing overhead
|
||||
chunksize = max(1, min(256, len(files) // args.workers))
|
||||
for i, h in enumerate(
|
||||
tqdm(
|
||||
pool.imap(hash_file, files, chunksize),
|
||||
desc="dedup",
|
||||
total=len(files),
|
||||
ncols=0,
|
||||
leave=(len(files) > 100000),
|
||||
)
|
||||
):
|
||||
if h in seen_hash:
|
||||
continue
|
||||
seen_hash.add(h)
|
||||
result.append(files[i])
|
||||
hash_list.append(h)
|
||||
return result, hash_list
|
||||
|
||||
|
||||
def is_afl_dir(dirnames, filenames):
|
||||
return (
|
||||
"queue" in dirnames
|
||||
and "hangs" in dirnames
|
||||
and "crashes" in dirnames
|
||||
and "fuzzer_setup" in filenames
|
||||
)
|
||||
|
||||
|
||||
def collect_files(input_paths):
|
||||
paths = []
|
||||
for s in input_paths:
|
||||
paths += glob.glob(s)
|
||||
|
||||
files = []
|
||||
with tqdm(desc="search", unit=" files", ncols=0) as pbar:
|
||||
for path in paths:
|
||||
for root, dirnames, filenames in os.walk(path, followlinks=True):
|
||||
for dirname in dirnames:
|
||||
if dirname.startswith("."):
|
||||
dirnames.remove(dirname)
|
||||
|
||||
if not args.crash_only and is_afl_dir(dirnames, filenames):
|
||||
continue
|
||||
|
||||
for filename in filenames:
|
||||
if filename.startswith("."):
|
||||
continue
|
||||
pbar.update(1)
|
||||
files.append(os.path.join(root, filename))
|
||||
return files
|
||||
|
||||
|
||||
def main():
|
||||
init()
|
||||
|
||||
files = collect_files(args.input)
|
||||
if len(files) == 0:
|
||||
logger.error("no inputs in the target directory - nothing to be done")
|
||||
sys.exit(1)
|
||||
logger.info("Found %d input files in %d directories", len(files), len(args.input))
|
||||
|
||||
if not args.no_dedup:
|
||||
files, hash_list = dedup(files)
|
||||
logger.info("Remain %d files after dedup", len(files))
|
||||
else:
|
||||
logger.info("Skipping file deduplication.")
|
||||
|
||||
global file_index_type_code
|
||||
file_index_type_code = detect_type_code(len(files))
|
||||
|
||||
logger.info("Sorting files.")
|
||||
with multiprocessing.Pool(args.workers) as pool:
|
||||
chunksize = max(1, min(512, len(files) // args.workers))
|
||||
size_list = list(pool.map(os.path.getsize, files, chunksize))
|
||||
idxes = sorted(range(len(files)), key=lambda x: size_list[x])
|
||||
files = [files[idx] for idx in idxes]
|
||||
hash_list = [hash_list[idx] for idx in idxes]
|
||||
|
||||
afl_map_size = None
|
||||
if b"AFL_DUMP_MAP_SIZE" in open(args.exe, "rb").read():
|
||||
output = subprocess.run(
|
||||
[args.exe], capture_output=True, env={"AFL_DUMP_MAP_SIZE": "1", "ASAN_OPTIONS": "detect_leaks=0"}
|
||||
).stdout
|
||||
afl_map_size = int(output)
|
||||
logger.info("Setting AFL_MAP_SIZE=%d", afl_map_size)
|
||||
|
||||
global tuple_index_type_code
|
||||
tuple_index_type_code = detect_type_code(afl_map_size * 9)
|
||||
|
||||
logger.info("Testing the target binary")
|
||||
tuples, _ = afl_showmap(files[0], afl_map_size=afl_map_size, first=True)
|
||||
if tuples:
|
||||
logger.info("ok, %d tuples recorded", len(tuples))
|
||||
else:
|
||||
logger.error("no instrumentation output detected")
|
||||
sys.exit(1)
|
||||
|
||||
job_queue = multiprocessing.Queue()
|
||||
progress_queue = multiprocessing.Queue()
|
||||
result_queue = multiprocessing.Queue()
|
||||
|
||||
workers = []
|
||||
for i in range(args.workers):
|
||||
p = Worker(i, afl_map_size, job_queue, progress_queue, result_queue)
|
||||
p.start()
|
||||
workers.append(p)
|
||||
|
||||
chunk = max(1, min(128, len(files) // args.workers))
|
||||
jobs = list(batched(enumerate(files), chunk))
|
||||
jobs += [None] * args.workers # sentinel
|
||||
|
||||
dispatcher = JobDispatcher(job_queue, jobs)
|
||||
dispatcher.start()
|
||||
|
||||
logger.info("Processing traces")
|
||||
effective = 0
|
||||
trace_info = {}
|
||||
for _ in tqdm(files, ncols=0, smoothing=0.01):
|
||||
r = progress_queue.get()
|
||||
if r is not None:
|
||||
idx, worker_idx, pos, tuple_count = r
|
||||
trace_info[idx] = worker_idx, pos, tuple_count
|
||||
effective += 1
|
||||
dispatcher.join()
|
||||
|
||||
logger.info("Obtaining trace results")
|
||||
ms = []
|
||||
crashes = []
|
||||
counter = collections.Counter()
|
||||
for _ in tqdm(range(args.workers), ncols=0):
|
||||
idx, m, c, crs = result_queue.get()
|
||||
ms.append(m)
|
||||
counter.update(c)
|
||||
crashes.extend(crs)
|
||||
workers[idx].join()
|
||||
best_idxes = list(map(min, zip(*ms)))
|
||||
|
||||
if not args.crash_dir:
|
||||
logger.info(
|
||||
"Found %d unique tuples across %d files (%d effective)",
|
||||
len(counter),
|
||||
len(files),
|
||||
effective,
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"Found %d unique tuples across %d files (%d effective, %d crashes)",
|
||||
len(counter),
|
||||
len(files),
|
||||
effective,
|
||||
len(crashes),
|
||||
)
|
||||
all_unique = counter.most_common()
|
||||
|
||||
logger.info("Processing candidates and writing output")
|
||||
already_have = set()
|
||||
count = 0
|
||||
|
||||
def save_file(idx):
|
||||
input_path = files[idx]
|
||||
fn = (
|
||||
base64.b16encode(hash_list[idx]).decode("utf8").lower()
|
||||
if not args.no_dedup
|
||||
else os.path.basename(input_path)
|
||||
)
|
||||
if args.as_queue:
|
||||
if args.no_dedup:
|
||||
fn = "id:%06d,orig:%s" % (count, fn)
|
||||
else:
|
||||
fn = "id:%06d,hash:%s" % (count, fn)
|
||||
output_path = os.path.join(args.output, fn)
|
||||
try:
|
||||
os.link(input_path, output_path)
|
||||
except OSError:
|
||||
shutil.copy(input_path, output_path)
|
||||
|
||||
jobs = [[] for i in range(args.workers)]
|
||||
saved = set()
|
||||
for t, c in all_unique:
|
||||
if c != 1:
|
||||
continue
|
||||
idx = best_idxes[t]
|
||||
if idx in saved:
|
||||
continue
|
||||
save_file(idx)
|
||||
saved.add(idx)
|
||||
count += 1
|
||||
|
||||
worker_idx, pos, tuple_count = trace_info[idx]
|
||||
job = (pos, tuple_count)
|
||||
jobs[worker_idx].append(job)
|
||||
|
||||
trace_packs = []
|
||||
workers = []
|
||||
for i in range(args.workers):
|
||||
pack_name = os.path.join(args.output, ".traces", f"{i}.pack")
|
||||
trace_f = open(pack_name, "rb")
|
||||
trace_packs.append(trace_f)
|
||||
|
||||
p = CombineTraceWorker(pack_name, jobs[i], result_queue)
|
||||
p.start()
|
||||
workers.append(p)
|
||||
|
||||
for _ in range(args.workers):
|
||||
result = result_queue.get()
|
||||
already_have.update(result)
|
||||
|
||||
for t, c in tqdm(list(reversed(all_unique)), ncols=0):
|
||||
if t in already_have:
|
||||
continue
|
||||
|
||||
idx = best_idxes[t]
|
||||
save_file(idx)
|
||||
count += 1
|
||||
|
||||
worker_idx, pos, tuple_count = trace_info[idx]
|
||||
trace_pack = trace_packs[worker_idx]
|
||||
trace_pack.seek(pos)
|
||||
result = array.array(tuple_index_type_code)
|
||||
result.fromfile(trace_pack, tuple_count)
|
||||
|
||||
already_have.update(result)
|
||||
|
||||
for f in trace_packs:
|
||||
f.close()
|
||||
|
||||
if args.crash_dir:
|
||||
logger.info("Saving crashes to %s", args.crash_dir)
|
||||
crash_files = [files[c] for c in crashes]
|
||||
|
||||
if args.no_dedup:
|
||||
# Unless we deduped previously, we have to dedup the crash files
|
||||
# now.
|
||||
crash_files, hash_list = dedup(crash_files)
|
||||
|
||||
for idx, crash_path in enumerate(crash_files):
|
||||
fn = base64.b16encode(hash_list[idx]).decode("utf8").lower()
|
||||
output_path = os.path.join(args.crash_dir, fn)
|
||||
try:
|
||||
os.link(crash_path, output_path)
|
||||
except OSError:
|
||||
try:
|
||||
shutil.copy(crash_path, output_path)
|
||||
except shutil.Error:
|
||||
# This error happens when src and dest are hardlinks of the
|
||||
# same file. We have nothing to do in this case, but handle
|
||||
# it gracefully.
|
||||
pass
|
||||
|
||||
if count == 1:
|
||||
logger.warning("all test cases had the same traces, check syntax!")
|
||||
logger.info('narrowed down to %s files, saved in "%s"', count, args.output)
|
||||
if not os.environ.get("AFL_KEEP_TRACES"):
|
||||
logger.info("Deleting trace files")
|
||||
trace_dir = os.path.join(args.output, ".traces")
|
||||
shutil.rmtree(trace_dir, ignore_errors=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -121,6 +121,7 @@ kernel.sched_child_runs_first=1
|
||||
kernel.sched_autogroup_enabled=1
|
||||
kernel.sched_migration_cost_ns=50000000
|
||||
kernel.sched_latency_ns=250000000
|
||||
vm.swappiness=10
|
||||
EOF
|
||||
}
|
||||
|
||||
@ -129,7 +130,7 @@ EOF
|
||||
if ! grep -E "^$KEY=" /etc/default/grub | grep -E -q 'noibrs pcid nopti'; then
|
||||
echo "Configuring performance boot options"
|
||||
LINE=`grep -E "^$KEY=" /etc/default/grub | sed "s/^$KEY=//" | tr -d '"'`
|
||||
OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
|
||||
OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off nokaslr no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"
|
||||
echo Setting boot options in /etc/default/grub to $KEY=\"$OPTIONS\"
|
||||
sed -i "s|^$KEY=.*|$KEY=\"$OPTIONS\"|" /etc/default/grub
|
||||
fi
|
||||
|
@ -41,6 +41,7 @@ if [ "$PLATFORM" = "Linux" ] ; then
|
||||
sysctl -w kernel.sched_autogroup_enabled=1
|
||||
sysctl -w kernel.sched_migration_cost_ns=50000000 2>/dev/null
|
||||
sysctl -w kernel.sched_latency_ns=250000000 2>/dev/null
|
||||
sysctl -w vm.swappiness=10 2>/dev/null
|
||||
echo never > /sys/kernel/mm/transparent_hugepage/enabled
|
||||
test -e /sys/devices/system/cpu/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/scaling_governor
|
||||
test -e /sys/devices/system/cpu/cpufreq/policy0/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/policy*/scaling_governor
|
||||
@ -54,7 +55,7 @@ if [ "$PLATFORM" = "Linux" ] ; then
|
||||
echo
|
||||
dmesg | grep -E -q 'noibrs pcid nopti' || {
|
||||
echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this:
|
||||
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"'
|
||||
echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off nokaslr no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"'
|
||||
echo
|
||||
}
|
||||
echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed.
|
||||
|
@ -115,7 +115,7 @@ PLATFORM=`uname -s`
|
||||
#if [ "$PLATFORM" = "Linux" ] ; then
|
||||
# CUR_TIME=`cat /proc/uptime | awk '{printf "%.0f\n", $1}'`
|
||||
#else
|
||||
# This will lead to inacurate results but will prevent the script from breaking on platforms other than Linux
|
||||
# This will lead to inaccurate results but will prevent the script from breaking on platforms other than Linux
|
||||
CUR_TIME=`date +%s`
|
||||
#fi
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# custum mutator: AFL++
|
||||
# custom mutator: AFL++
|
||||
|
||||
this is the AFL++ havoc mutator as a custom mutator module for AFL++.
|
||||
|
||||
|
@ -4,7 +4,7 @@ CFLAGS = -O3 -funroll-loops -fPIC
|
||||
all: aflpp-standalone
|
||||
|
||||
aflpp-standalone: aflpp-standalone.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
|
||||
$(CC) $(CFLAGS) -w -DBIN_PATH=\"foo\" -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c ../../../src/afl-fuzz-extras.c ../../../src/afl-common.c
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ aflpp-standalone core
|
||||
|
@ -409,7 +409,7 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size,
|
||||
|
||||
} else {
|
||||
|
||||
// new_size fits into buf, so re-use it
|
||||
// new_size fits into buf, so reuse it
|
||||
*out_buf = buf;
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,20 @@
|
||||
|
||||
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-implicit-function-declaration
|
||||
CFLAGS = -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1 -Wno-pointer-sign
|
||||
CXXFLAGS= -g -O3 -funroll-loops -fPIC -D_STANDALONE_MODULE=1
|
||||
|
||||
all: autotokens-standalone
|
||||
|
||||
autotokens.o: ../autotokens.cpp
|
||||
$(CXX) $(CXXFLAGS) -I../../../include -I. -I../.. -c ../autotokens.cpp
|
||||
$(CXX) $(CXXFLAGS) -g -I../../../include -I. -I../.. -c ../autotokens.cpp
|
||||
|
||||
autotokens-standalone: autotokens-standalone.c autotokens.o
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
|
||||
$(CC) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
|
||||
$(CXX) $(CFLAGS) -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c autotokens-standalone.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-performance.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-extras.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-fuzz-queue.c
|
||||
$(CC) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -c ../../../src/afl-common.c
|
||||
$(CXX) $(CFLAGS) -g -DBIN_PATH=\"foo\" -I../../../include -I. -o autotokens-standalone *.o
|
||||
@rm -f ../../../src/afl-common.o ../../../src/afl-fuzz-queue.o ../../../src/afl-fuzz-extras.o ../../../src/afl-performance.o
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ autotokens-standalone core
|
||||
|
@ -7,6 +7,6 @@ just type `make` to build.
|
||||
You *MUST* use a dictionary file to have an effective grammarless grammar fuzzer!
|
||||
|
||||
```
|
||||
autotokens-standalone -h # to see all parameteres
|
||||
autotokens-standalone -h # to see all parameters
|
||||
autotokens-standalone -x foo.dict inputfile outputfile # example
|
||||
```
|
||||
|
@ -1,15 +1,28 @@
|
||||
#include "afl-fuzz.h"
|
||||
#include "afl-mutations.h"
|
||||
#include "forkserver.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
static int max_havoc = 16, verbose;
|
||||
static unsigned char *dict, *mh = "16";
|
||||
static char _mh[4] = "16";
|
||||
static char *dict, *mh = _mh;
|
||||
|
||||
extern int module_disabled;
|
||||
|
||||
void *afl_custom_init(afl_state_t *, unsigned int);
|
||||
u8 afl_custom_queue_get(void *data, const u8 *filename);
|
||||
size_t afl_custom_fuzz(void *data, u8 *buf, size_t buf_size, u8 **out_buf,
|
||||
u8 *add_buf, size_t add_buf_size, size_t max_size);
|
||||
|
||||
u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
|
||||
return 0;
|
||||
}
|
||||
fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
|
||||
u32 i) {
|
||||
return FSRV_RUN_OK;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@ -144,7 +157,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (dict) {
|
||||
|
||||
load_extras(afl, dict);
|
||||
load_extras(afl, (u8*)dict);
|
||||
if (verbose)
|
||||
fprintf(stderr, "Loaded dictionary: %s (%u entries)\n", dict,
|
||||
afl->extras_cnt);
|
||||
|
@ -3,8 +3,7 @@
|
||||
These are example and helper files for the custom mutator feature.
|
||||
See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information
|
||||
|
||||
Note that if you compile with python3.7 you must use python3 scripts, and if
|
||||
you use python2.7 to compile python2 scripts!
|
||||
Note that if you compile with python3.7 you must use python3 scripts.
|
||||
|
||||
simple_example.c - most simplest example. generates a random sized buffer
|
||||
filled with 'A'
|
||||
|
@ -304,7 +304,7 @@ class XmlMutatorMin:
|
||||
|
||||
# Log something
|
||||
if self.verbose:
|
||||
print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag))
|
||||
print("Resetting tag #%i '%s'" % (rand_elem_id, rand_elem.tag))
|
||||
|
||||
# Reset the node
|
||||
rand_elem.clear()
|
||||
|
@ -80,12 +80,12 @@ def fuzz(buf, add_buf, max_size):
|
||||
via_buffer = False
|
||||
log("fuzz(): Can't initialize mutator with AFL buffer")
|
||||
|
||||
# If init from AFL buffer wasn't succesful
|
||||
# If init from AFL buffer wasn't successful
|
||||
if not via_buffer:
|
||||
log("fuzz(): Returning unmodified AFL buffer")
|
||||
return buf
|
||||
|
||||
# Sucessful initialization -> mutate
|
||||
# Successful initialization -> mutate
|
||||
try:
|
||||
__mutator__.mutate(max=5)
|
||||
log("fuzz(): Input mutated")
|
||||
|
@ -56,7 +56,7 @@ if [ ! -f "../../src/afl-performance.o" ]; then
|
||||
|
||||
fi
|
||||
|
||||
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
|
||||
PYTHONBIN=`command -v python3 || command -v python || echo python3`
|
||||
MAKECMD=make
|
||||
TARCMD=tar
|
||||
|
||||
@ -143,7 +143,7 @@ test -e json-c/.libs/libjson-c.a || {
|
||||
echo
|
||||
echo
|
||||
echo "[+] Json-c successfully prepared!"
|
||||
echo "[+] Builing gramatron now."
|
||||
echo "[+] Building gramatron now."
|
||||
$CC -O3 -g -fPIC -Wno-unused-result -Wl,--allow-multiple-definition -I../../include -o gramatron.so -shared -I. -I/prg/dev/include gramfuzz.c gramfuzz-helpers.c gramfuzz-mutators.c gramfuzz-util.c hashmap.c ../../src/afl-performance.o json-c/.libs/libjson-c.a || exit 1
|
||||
echo
|
||||
echo "[+] gramatron successfully built!"
|
||||
|
@ -52,7 +52,7 @@ if [ ! -f "../../config.h" ]; then
|
||||
|
||||
fi
|
||||
|
||||
PYTHONBIN=`command -v python3 || command -v python || command -v python2 || echo python3`
|
||||
PYTHONBIN=`command -v python3 || command -v python || echo python3`
|
||||
MAKECMD=make
|
||||
TARCMD=tar
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# custum mutator: honggfuzz mangle
|
||||
# custom mutator: honggfuzz mangle
|
||||
|
||||
this is the honggfuzz mutator in mangle.c as a custom mutator
|
||||
module for AFL++. It is the original mangle.c, mangle.h and honggfuzz.h
|
||||
|
@ -850,7 +850,7 @@ static void mangle_ASCIINumChange(run_t *run, bool printable) {
|
||||
|
||||
size_t len = 0;
|
||||
uint64_t val = 0;
|
||||
/* 20 is maximum lenght of a string representing a 64-bit unsigned value */
|
||||
/* 20 is maximum length of a string representing a 64-bit unsigned value */
|
||||
for (len = 0; (len < 20) && (len < left); len++) {
|
||||
|
||||
char c = run->dynfile->data[off + len];
|
||||
|
@ -40,7 +40,7 @@ bool BlockCoverage::AppendCoverage(const std::string &S) {
|
||||
// Coverage lines have this form:
|
||||
// CN X Y Z T
|
||||
// where N is the number of the function, T is the total number of instrumented
|
||||
// BBs, and X,Y,Z, if present, are the indecies of covered BB.
|
||||
// BBs, and X,Y,Z, if present, are the indices of covered BB.
|
||||
// BB #0, which is the entry block, is not explicitly listed.
|
||||
bool BlockCoverage::AppendCoverage(std::istream &IN) {
|
||||
|
||||
|
@ -106,7 +106,7 @@ private:
|
||||
};
|
||||
|
||||
// Parses one dictionary entry.
|
||||
// If successful, write the enty to Unit and returns true,
|
||||
// If successful, write the entry to Unit and returns true,
|
||||
// otherwise returns false.
|
||||
bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
|
||||
// Parses the dictionary file, fills Units, returns true iff all lines
|
||||
|
@ -427,7 +427,7 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
|
||||
|
||||
Env.RunOneMergeJob(Job.get());
|
||||
|
||||
// Continue if our crash is one of the ignorred ones.
|
||||
// Continue if our crash is one of the ignored ones.
|
||||
if (Options.IgnoreTimeouts && ExitCode == Options.TimeoutExitCode)
|
||||
Env.NumTimeouts++;
|
||||
else if (Options.IgnoreOOMs && ExitCode == Options.OOMExitCode)
|
||||
|
@ -452,7 +452,7 @@ void CrashResistantMerge(const Vector<std::string> &Args,
|
||||
auto ExitCode = ExecuteCommand(Cmd);
|
||||
if (!ExitCode) {
|
||||
|
||||
VPrintf(V, "MERGE-OUTER: succesfull in %zd attempt(s)\n", Attempt);
|
||||
VPrintf(V, "MERGE-OUTER: succesful in %zd attempt(s)\n", Attempt);
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -498,9 +498,9 @@ size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
|
||||
T Add = Rand(21);
|
||||
Add -= 10;
|
||||
if (Rand.RandBool())
|
||||
Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes.
|
||||
Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endianness.
|
||||
else
|
||||
Val = Val + Add; // Add assuming current endiannes.
|
||||
Val = Val + Add; // Add assuming current endianness.
|
||||
if (Add == 0 || Rand.RandBool()) // Maybe negate.
|
||||
Val = -Val;
|
||||
|
||||
|
@ -460,7 +460,7 @@ static size_t InternalStrnlen(const char *S, size_t MaxLen) {
|
||||
}
|
||||
|
||||
// Finds min of (strlen(S1), strlen(S2)).
|
||||
// Needed bacause one of these strings may actually be non-zero terminated.
|
||||
// Needed because one of these strings may actually be non-zero terminated.
|
||||
static size_t InternalStrnlen2(const char *S1, const char *S2) {
|
||||
|
||||
size_t Len = 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
# custum mutator: libfuzzer LLVMFuzzerMutate()
|
||||
# custom mutator: libfuzzer LLVMFuzzerMutate()
|
||||
|
||||
This uses the libfuzzer LLVMFuzzerMutate() function in llvm 12.
|
||||
|
||||
|
@ -2,7 +2,7 @@ CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
all: radamsa-mutator.so
|
||||
|
||||
# These can be overriden:
|
||||
# These can be overridden:
|
||||
CFLAGS ?= $(CFLAGS_FLTO)
|
||||
|
||||
# These are required: (otherwise radamsa gets very very slooooow)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# custum mutator: libradamsa
|
||||
# custom mutator: libradamsa
|
||||
|
||||
Pretranslated radamsa library. This code belongs to the radamsa author.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# custum mutator: symcc
|
||||
# custom mutator: symcc
|
||||
|
||||
This uses the symcc to find new paths into the target.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# custum mutator: symqemu
|
||||
# custom mutator: symqemu
|
||||
|
||||
This uses the symcc to find new paths into the target.
|
||||
|
||||
|
@ -3,6 +3,73 @@
|
||||
This is the list of all noteworthy changes made in every public
|
||||
release of the tool. See README.md for the general instruction manual.
|
||||
|
||||
|
||||
### Version ++4.33a (dev)
|
||||
- afl-fuzz:
|
||||
- Use `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT` if you use AFL_PRELOAD
|
||||
to disable fork, see docs (thanks to @alexandredoyen29)
|
||||
- Fix for FAST power schedules (introduced in 4.32c) (thanks to @kcwu)
|
||||
- Colors for NO_UI output (thanks to @smoelius)
|
||||
- Fix potential sync issues when resuming sessions and when instances in a
|
||||
campaign are restarted and skip entries that were synced from itself
|
||||
(thanks to @kcwu for raising the issues and providing support!)
|
||||
- more 64 bit archicture support by @maribu
|
||||
- afl-cc:
|
||||
- Added instrumenting hidden edges (approx 5% edges were not instrumented,
|
||||
LLVM sancov overall misses 8% of edges compared to our implementation)
|
||||
Note that is is currently only implemented for our PCGUARD plugin, not
|
||||
LTO, CLASSIC, etc.!
|
||||
- Fix to make AFL_SAN_NO_INST work with gcc_plugin
|
||||
- MacOS aflpp driver compilation fix (-fsanitize=fuzzer implementation)
|
||||
- Make AFL_DUMP_MAP_SIZE work even if the target has sanitizer issues
|
||||
- qemuafl:
|
||||
- Better MIPS persistent mode support
|
||||
- `AFL_EXITPOINT` support added
|
||||
- `AFL_QEMU_BLOCK_COV` block coverage support added
|
||||
- afl-cmin:
|
||||
- New afl-cmin.py which is much faster, will be executed by default via
|
||||
afl-cmin if it executes successfully (thanks to @kcwu!)
|
||||
- New desocketing library: utils/libaflppdesock
|
||||
- Likely works when all other desocketing options fail
|
||||
|
||||
|
||||
### Version ++4.32c (release)
|
||||
- Fixed a bug where after a fast restart of a full fuzzed corpus afl-fuzz
|
||||
terminates with "need at least one valid input seed that does not crash"
|
||||
- Small improvements to afl-*-config
|
||||
- afl-fuzz:
|
||||
- memory leak fixes by @kcwu - thanks!
|
||||
- many more nits and small memory saves thanks to @kcwu
|
||||
- remove deprecated files from queue/.state
|
||||
- fix bitmap update function if no current trace is present
|
||||
- fix for afl_custom_queue_get
|
||||
- various small nits
|
||||
- afl-cc:
|
||||
- fix pass support for LLVM 20 (passes were run too early)
|
||||
- dropped plugin support for LLVM 13
|
||||
- fix AFL_OLD_FORKSERVER
|
||||
- various minor fixes
|
||||
- frida_mode:
|
||||
- fixes for new MacOS + M4 hardware
|
||||
|
||||
### Version ++4.31c (release)
|
||||
- SAND mode added (docs/SAND.md) for more effecient fuzzing with sanitizers
|
||||
(thanks to @wtdcode !)
|
||||
- afl-fuzz:
|
||||
- splicing phase is now DISABLED by default because research showed
|
||||
it is counterproductive. New command line parameter `-u` to enable
|
||||
it.
|
||||
- Python 3.13+ support
|
||||
- loose file and shared memory permissions on Android and iPhone
|
||||
- afl-cc:
|
||||
- LLVM 20 support (again - please don't change the API all the time ...)
|
||||
- -fsanitize=fuzzer now inserts libAFLDriver.a addtionally early to help
|
||||
compiling if LLVMFuzzerTestOneOnput is in an .a archive
|
||||
- added __sanitizer_weak_hook_* functions (in case that is helpful in
|
||||
weird setups)
|
||||
- fix bug with large map sizes when multiple libraries are loaded after
|
||||
the shared memory was obtained.
|
||||
|
||||
### Version ++4.30c (release)
|
||||
! afl-gcc and afl-clang funcionality is now removed !
|
||||
- afl-fuzz:
|
||||
|
18
docs/FAQ.md
18
docs/FAQ.md
@ -11,7 +11,7 @@ If you find an interesting or important question missing, submit it via
|
||||
AFL++ is a superior fork to Google's AFL - more speed, more and better
|
||||
mutations, more and better instrumentation, custom module support, etc.
|
||||
|
||||
American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting
|
||||
American Fuzzy Lop (AFL) was developed by Michal "lcamtuf" Zalewski starting
|
||||
in 2013/2014, and when he left Google end of 2017 he stopped developing it.
|
||||
|
||||
At the end of 2019, the Google fuzzing team took over maintenance of AFL,
|
||||
@ -106,7 +106,7 @@ If you find an interesting or important question missing, submit it via
|
||||
<details>
|
||||
<summary id="should-you-ever-stop-afl-fuzz-minimize-the-corpus-and-restart">Should you ever stop afl-fuzz, minimize the corpus and restart?</summary><p>
|
||||
|
||||
To stop afl-fuzz, minimize it's corpus and restart you would usually do:
|
||||
To stop afl-fuzz, minimize its corpus and restart you would usually do:
|
||||
|
||||
```
|
||||
Control-C # to terminate afl-fuzz
|
||||
@ -236,7 +236,7 @@ If you find an interesting or important question missing, submit it via
|
||||
[AFLFast](https://github.com/mboehme/aflfast), however, modified to be more
|
||||
effective and several more modes added.
|
||||
|
||||
The most effective modes are `-p fast` (default) and `-p explore`.
|
||||
The most effective modes are `-p explore` (default) and `-p fast`.
|
||||
|
||||
If you fuzz with several parallel afl-fuzz instances, then it is beneficial
|
||||
to assign a different schedule to each instance, however the majority should
|
||||
@ -274,7 +274,7 @@ If you find an interesting or important question missing, submit it via
|
||||
the existing map will be used also for the newly loaded libraries, which
|
||||
allows it to work, however, the efficiency of the fuzzing will be partially
|
||||
degraded. Note that there is additionally `AFL_IGNORE_PROBLEMS_COVERAGE` to
|
||||
additionally tell AFL++ to ignore any coverage from the late loaded libaries.
|
||||
additionally tell AFL++ to ignore any coverage from the late loaded libraries.
|
||||
</p></details>
|
||||
|
||||
<details>
|
||||
@ -284,14 +284,14 @@ If you find an interesting or important question missing, submit it via
|
||||
afl-cc/afl-clang-fast/afl-clang-lto:
|
||||
|
||||
```
|
||||
/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
|
||||
clang-13: error: unable to execute command: No such file or directory
|
||||
clang-13: error: clang frontend command failed due to signal (use -v to see invocation)
|
||||
clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
|
||||
/prg/tmp/llvm-project/build/bin/clang-18: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv
|
||||
clang-18: error: unable to execute command: No such file or directory
|
||||
clang-18: error: clang frontend command failed due to signal (use -v to see invocation)
|
||||
clang version 18.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad)
|
||||
Target: x86_64-unknown-linux-gnu
|
||||
Thread model: posix
|
||||
InstalledDir: /prg/tmp/llvm-project/build/bin
|
||||
clang-13: note: diagnostic msg:
|
||||
clang-18: note: diagnostic msg:
|
||||
********************
|
||||
```
|
||||
|
||||
|
@ -21,7 +21,7 @@ If you want to build AFL++ yourself, you have many options. The easiest choice
|
||||
is to build and install everything:
|
||||
|
||||
NOTE: depending on your Debian/Ubuntu/Kali/... release, replace `-14` with
|
||||
whatever llvm version is available. We recommend llvm 13 or newer.
|
||||
whatever llvm version is available. We recommend llvm 14 or newer.
|
||||
|
||||
```shell
|
||||
sudo apt-get update
|
||||
@ -90,7 +90,6 @@ These build options exist:
|
||||
* PROFILING - compile afl-fuzz with profiling information
|
||||
* INTROSPECTION - compile afl-fuzz with mutation introspection
|
||||
* NO_PYTHON - disable python support
|
||||
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
* NO_UTF - do not use UTF-8 for line rendering in status screen (fallback to G1 box drawing, of vanilla AFL)
|
||||
* NO_NYX - disable building nyx mode dependencies
|
||||
* NO_CORESIGHT - disable building coresight (arm64 only)
|
||||
@ -170,3 +169,47 @@ and definitely don't look POSIX-compliant. This means two things:
|
||||
User emulation mode of QEMU does not appear to be supported on macOS, so
|
||||
black-box instrumentation mode (`-Q`) will not work. However, FRIDA mode (`-O`)
|
||||
works on both x86 and arm64 macOS boxes.
|
||||
|
||||
## iOS on arm64 and arm64e
|
||||
|
||||
**Option 1: Compilation on jailbroken iOS (recommended)**
|
||||
|
||||
To compile directly on a jailbroken iOS device, it is recommended to use a jailbreak that supports Procursus,
|
||||
as Procursus provides up-to-date pre-built packages for the required tools.
|
||||
|
||||
Ensure `openssh` is installed on your iOS device, then SSH into it.
|
||||
Install the following packages:
|
||||
|
||||
```shell
|
||||
sudo apt install wget git make cmake clang gawk llvm ldid coreutils build-essential xz-utils
|
||||
```
|
||||
|
||||
Configure the environment for compilation:
|
||||
|
||||
```shell
|
||||
export IOS_SDK_PATH="/usr/share/SDKs/iPhoneOS.sdk"
|
||||
export CC=clang
|
||||
export CXX=clang++
|
||||
```
|
||||
|
||||
Then build following the general Linux instructions.
|
||||
|
||||
**Option 2: Cross-Compilation on macOS for Jailbroken iOS**
|
||||
|
||||
In addition to the packages required for a macOS build, install `ldid` for signing binaries:
|
||||
|
||||
```shell
|
||||
brew install ldid-procursus
|
||||
```
|
||||
|
||||
Configure the environment for compilation:
|
||||
|
||||
```shell
|
||||
export IOS_SDK_PATH="$(xcrun --sdk iphoneos --show-sdk-path)"
|
||||
export CC="$(xcrun --sdk iphoneos -f clang) -target arm64-apple-ios14.0"
|
||||
export CXX="$(xcrun --sdk iphoneos -f clang++) -target arm64-apple-ios14.0"
|
||||
export HOST_CC=cc
|
||||
```
|
||||
|
||||
Then build following the general Linux instructions.
|
||||
Finally, transfer the binaries to your iOS device.
|
||||
|
81
docs/SAND.md
Normal file
81
docs/SAND.md
Normal file
@ -0,0 +1,81 @@
|
||||
# SAND: Decoupling Sanitization from Fuzzing for Low Overhead
|
||||
|
||||
- Authors: Ziqiao Kong, Shaohua Li, Heqing Huang, Zhendong Su
|
||||
- Maintainer: [Ziqiao Kong](https://github.com/wtdcode)
|
||||
- Preprint: [arXiv](https://arxiv.org/abs/2402.16497), accepted by ICSE 2025
|
||||
- Main repo (for paper, reproduction, reference or cite): https://github.com/wtdcode/sand-aflpp
|
||||
|
||||
## Motivation
|
||||
|
||||
SAND introduces a new fuzzing workflow that can greatly reduce (or even eliminate) sanitizer overhead and combine different sanitizers in one fuzzing campaign.
|
||||
|
||||
The key point of SAND is that: sanitizing all inputs is wasting fuzzing power, because bug-triggering inputs are extremely rare (~1%). Obviously, not all inputs worth going through sanitizers. Therefore, if we can somehow "predict" if an input could trigger bugs (defined as "execution pattern"), we could greatly save fuzzing power by only sanitizing a small proportion of all inputs. That's exactly how SAND works.
|
||||
|
||||
## Usage
|
||||
|
||||
For a normal fuzzing workflow, we have:
|
||||
|
||||
1. Build target project with AFL_USE_ASAN=1 to get `target_asan`
|
||||
2. Fuzz the target with `afl-fuzz -i seeds -o out -- ./target_asan`
|
||||
|
||||
For SAND fuzzing workflow, this is slightly different:
|
||||
|
||||
1. Build target project _without_ any sanitizers to get `target_native`, which we will define as a "native binary". It is usually done by using `afl-clang-fast/lto(++)` to compile your project _without_ `AFL_USE_ASAN/UBSAN/MSAN`.
|
||||
2. Build target project with AFL_USE_ASAN=1 AFL_LLVM_ONLY_FSRV=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
|
||||
3. Fuzz the target with `afl-fuzz -i seeds -o out -w ./target_asan -- ./target_native`. Note `-w` can be specified multiple times.
|
||||
|
||||
Then you get:
|
||||
|
||||
- almost the same performance as `afl-fuzz -i seeds -o out -- ./target_native`
|
||||
- and the same bug-finding capability as `afl-fuzz -i seeds -o out -- ./target_asan`
|
||||
|
||||
## Example Workflow
|
||||
|
||||
Take [test-instr.c](../test-instr.c) as an example.
|
||||
|
||||
1. Build the native binary
|
||||
|
||||
```bash
|
||||
afl-clang-fast test-instr.c -o ./native
|
||||
```
|
||||
|
||||
Just like the normal building process, except using `afl-clang-fast`
|
||||
|
||||
2. Build the sanitizers-enabled binaries.
|
||||
|
||||
```bash
|
||||
AFL_LLVM_ONLY_FSRV=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
|
||||
AFL_LLVM_ONLY_FSRV=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
|
||||
```
|
||||
|
||||
Do note `AFL_LLVM_ONLY_FSRV=1` is crucial, this enables forkservers but disables pc instrumentation. You are allowed to reuse sanitizers-enabled binaries, i.e. binaries built _without_ `AFL_LLVM_ONLY_FSRV=1`, at a cost of reduced speed.
|
||||
|
||||
3. Start fuzzing
|
||||
|
||||
```bash
|
||||
mkdir /tmp/test
|
||||
echo "a" > /tmp/test/a
|
||||
AFL_NO_UI=1 AFL_SKIP_CPUFREQ=1 afl-fuzz -i /tmp/test -o /tmp/out -w ./asanubsan -w ./msan -- ./native @@
|
||||
```
|
||||
|
||||
That's it!
|
||||
|
||||
## Tips
|
||||
|
||||
### Alternative execution patterns
|
||||
|
||||
By default, SAND uses the hash value of the simplified coverage map as execution pattern, i.e. if an input has a unique simplefied coverage map, it will be sent to sanitizers for inspection. This shall work for most cases. However, if you are strongly worried about missing bugs, try `AFL_SAN_ABSTRACTION=unique_trace afl-fuzz ...`, which filters inputs having a _unique coverage map_. Do note this significantly increases the number of inputs by 4-10 times, leading to much lower throughput. Alternatively, SAND also supports `AFL_SAN_ABSTRACTION=coverage_increase`, which essentially equals to running sanitizers on the corpus and thus having almost zero overhead, but at a cost of missing ~15% bugs in our evaluation.
|
||||
|
||||
### Run as many sanitizers as possible
|
||||
|
||||
Though we just used ASAN as an example, SAND works best if you provide more sanitizers, for example, UBSAN and MSAN.
|
||||
|
||||
You might do it via `afl-fuzz -i seeds -o out -w ./target_asan -w ./target_msan -w ./target_ubsan -- ./target_native`. Don't worry about the slow sanitizers like MSAN, SAND could still run very fast because only rather a few inputs are sanitized.
|
||||
|
||||
### Bugs types
|
||||
|
||||
The execution pattern evaluated in our papers is targeting the common bugs, as ASAN/MSAN/UBSAN catches. For other bug types, you probably need to define new execution patterns and re-evaluate.
|
||||
|
||||
### My throughput is greatly impacted
|
||||
|
||||
Generally, this is due to too many inputs going through sanitizers, for example, because of unstable targets. You could check stats from `plot_file` to confirm this. Try to switch execution patterns as stated above.
|
@ -6,7 +6,7 @@ coverage to effortlessly pick up subtle, local-scale changes to program control
|
||||
flow.
|
||||
|
||||
Note: If you are interested in a more current up-to-date deep dive how AFL++
|
||||
works then we commend this blog post:
|
||||
works then we recommend this blog post:
|
||||
[https://blog.ritsec.club/posts/afl-under-hood/](https://blog.ritsec.club/posts/afl-under-hood/)
|
||||
|
||||
Simplifying a bit, the overall algorithm can be summed up as:
|
||||
@ -385,10 +385,6 @@ there are several things to look at:
|
||||
subsequent iterations (e.g., due to incomplete clean-up or reinitialization of
|
||||
the state) and that most of the fuzzing effort goes to waste.
|
||||
|
||||
The paths where variable behavior is detected are marked with a matching entry
|
||||
in the `<out_dir>/queue/.state/variable_behavior/` directory, so you can look
|
||||
them up easily.
|
||||
|
||||
### CPU load
|
||||
|
||||
```
|
||||
|
@ -151,7 +151,7 @@ def deinit(): # optional for Python
|
||||
splicing - or anything else - and can also be ignored. If you are not
|
||||
using this additional data then define `splice_optout` (see above).
|
||||
This function is optional.
|
||||
Returing a length of 0 is valid and is interpreted as skipping this
|
||||
Returning a length of 0 is valid and is interpreted as skipping this
|
||||
one mutation result.
|
||||
For non-Python: the returned output buffer is under **your** memory
|
||||
management!
|
||||
|
@ -107,9 +107,14 @@ fairly broad use of environment variables instead:
|
||||
conditions
|
||||
- `AFL_USE_UBSAN=1` - activates the undefined behavior sanitizer
|
||||
- `AFL_UBSAN_VERBOSE=1` - outputs detailed diagnostic information when undefined behavior is detected, instead of simply terminating with "Illegal Instruction"
|
||||
. `AFL_USE_RTSAN` . activates the realtime sanitizer (realtime violations in deterministic run time constraints). (clang 20 minimum)
|
||||
|
||||
- Note: both `AFL_CFISAN_VERBOSE=1` and `AFL_UBSAN_VERBOSE=1` are disabled by default as verbose output can significantly slow down fuzzing performance. Use these options only during debugging or when additional crash diagnostics are required
|
||||
|
||||
- `AFL_LLVM_ONLY_FSRV`/`AFL_GCC_ONLY_FSRV` will inject forkserver but not pc instrumentation. Please note this is different compared to `AFL_LLVM_DISABLE_INSTRUMENTATION`, which will totally disable forkserver implementation. This env is pretty useful in two cases:
|
||||
- [SAND](./SAND.md). In this case, the binaries built in this way will serve as extra oracles. Check the corresponding documents for details.
|
||||
- Compatible with LibAFL ForkserverExecutor implementation and thus faster to repeatedly run, compared to simple CommandExecutor.
|
||||
|
||||
- `TMPDIR` is used by afl-as for temporary files; if this variable is not set,
|
||||
the tool defaults to /tmp.
|
||||
|
||||
@ -247,7 +252,7 @@ used if several separated instrumentations are performed which are then later
|
||||
combined.
|
||||
|
||||
- `AFL_LLVM_LTO_CALLER` activates collision free CALLER instrumentation
|
||||
- `AFL_LLVM_LTO_CALLER` sets the maximum mumber of single block functions
|
||||
- `AFL_LLVM_LTO_CALLER` sets the maximum number of single block functions
|
||||
to dig deeper into a real function. Default 0.
|
||||
- `AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge ID was given
|
||||
to which function. This helps to identify functions with variable bytes or
|
||||
@ -663,6 +668,41 @@ checks or alter some of the more exotic semantics of the tool:
|
||||
Note that will not be exact and with slow targets it can take seconds
|
||||
until there is a slice for the time test.
|
||||
|
||||
- When using `AFL_PRELOAD` with a preload that disable `fork()` calls in
|
||||
the target, the forkserver becomes unable to fork.
|
||||
To overcome this issue, the `AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT`
|
||||
permits to be able to check in the preloaded library if the environment
|
||||
variable `AFL_FORKSERVER_PARENT` is set, to be able to use vanilla
|
||||
`fork()` in the forkserver, and the placeholder in the target.
|
||||
Here is a POC :
|
||||
```C
|
||||
// AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT=1 afl-fuzz ...
|
||||
pid_t fork(void)
|
||||
{
|
||||
if (getenv("AFL_FORKSERVER_PARENT") == NULL)
|
||||
return 0; // We are in the target
|
||||
else
|
||||
return real_fork(); // We are in the forkserver
|
||||
}
|
||||
```
|
||||
|
||||
- `AFL_FORKSRV_UID` allows you to specify the UID that should be used when
|
||||
running the fork server. When setting this variable, user should ensure
|
||||
afl-fuzz binary has enough privileges to modify the UID (e.g. CAP\_SETUID
|
||||
capability in Linux system).
|
||||
|
||||
- `AFL_FORKSRV_GID` allows you to specify the GID and the supplementary group
|
||||
IDs that should be used when running the fork server. When setting this
|
||||
variable, user should ensure afl-fuzz binary has enough privileges to
|
||||
modify the GIDs (e.g. CAP\_SETGID capability in Linux system).
|
||||
|
||||
- When both `AFL_FORKSRV_UID` and `AFL_FORKSRV_GID` are set, afl-fuzz binary
|
||||
and the fork server no longer share any IDs. Thus, afl-fuzz binary changes
|
||||
the group owner of the created files to ensure that the fork server can
|
||||
still access them. In such case, user should ensure afl-fuzz binary has
|
||||
enough privileges to modify the ownership of entities (e.g. CAP\_CHOWN
|
||||
capability in Linux system).
|
||||
|
||||
## 6) Settings for afl-qemu-trace
|
||||
|
||||
The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
@ -701,6 +741,10 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
|
||||
of the basic blocks, which can be useful when dealing with very complex
|
||||
binaries.
|
||||
|
||||
- You can switch to block coverage that has less chances of colliding (but
|
||||
on the other hand coverage is on blocks, not edges) with
|
||||
`AFL_QEMU_BLOCK_COV`.
|
||||
|
||||
- Setting `AFL_QEMU_COMPCOV` enables the CompareCoverage tracing of all cmp
|
||||
and sub in x86 and x86_64. This is an alias of `AFL_COMPCOV_LEVEL=1` when
|
||||
`AFL_COMPCOV_LEVEL` is not specified.
|
||||
|
@ -45,7 +45,7 @@ E. CmpLog is our enhanced
|
||||
implementation, see
|
||||
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md)
|
||||
|
||||
F. Similar and compatible to clang 13+ sancov sanitize-coverage-allow/deny but
|
||||
F. Similar and compatible to clang 14+ sancov sanitize-coverage-allow/deny but
|
||||
for all llvm versions and all our compile modes, only instrument what should
|
||||
be instrumented, for more speed, directed fuzzing and less instability; see
|
||||
[instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md)
|
||||
@ -106,6 +106,7 @@ Among others, the following features and patches have been integrated:
|
||||
* Win32 PE binary-only fuzzing with QEMU and Wine
|
||||
* AFLfast's power schedules by Marcel Böhme:
|
||||
[https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
|
||||
* The fast deterministic stage by Han Zheng: [https://github.com/hexhive/mendelFuzz-Artifact/](https://github.com/hexhive/mendelFuzz-Artifact/)
|
||||
* The MOpt mutator:
|
||||
[https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
|
||||
* LLVM mode Ngram coverage by Adrian Herrera
|
||||
|
@ -16,7 +16,8 @@ FRIDA mode and QEMU mode in persistent mode are the fastest - if persistent mode
|
||||
is possible and the stability is high enough.
|
||||
|
||||
Otherwise, try Zafl, RetroWrite, Dyninst, and if these fail, too, then try
|
||||
standard FRIDA/QEMU mode with `AFL_ENTRYPOINT` to where you need it.
|
||||
standard FRIDA/QEMU mode with `AFL_ENTRYPOINT` + `AFL_EXITPOINT` to where you
|
||||
need it.
|
||||
|
||||
If your target is non-linux, then use unicorn_mode.
|
||||
|
||||
@ -196,7 +197,7 @@ afl-clang-fast's.
|
||||
|
||||
RetroWrite is a static binary rewriter that can be combined with AFL++. If you
|
||||
have an x86_64 or arm64 binary that does not contain C++ exceptions and - if
|
||||
x86_64 - still has it's symbols and compiled with position independent code
|
||||
x86_64 - still has its symbols and compiled with position independent code
|
||||
(PIC/PIE), then the RetroWrite solution might be for you.
|
||||
It decompiles to ASM files which can then be instrumented with afl-gcc.
|
||||
Note that afl-gcc is only present until AFL++ v4.21c and was subsequently removed as it is obsolete.
|
||||
|
@ -132,11 +132,15 @@ options are available:
|
||||
locations. This technique is very fast and good - if the target does not
|
||||
transform input data before comparison. Therefore, this technique is called
|
||||
`input to state` or `redqueen`. If you want to use this technique, then you
|
||||
have to compile the target twice, once specifically with/for this mode by
|
||||
setting `AFL_LLVM_CMPLOG=1`, and pass this binary to afl-fuzz via the `-c`
|
||||
parameter. Note that you can compile also just a cmplog binary and use that
|
||||
for both, however, there will be a performance penalty. You can read more
|
||||
about this in
|
||||
have to compile the target with `AFL_LLVM_CMPLOG=1`.
|
||||
You could use the resulting binary for both normal fuzzing and `-c` CMPLOG
|
||||
mode (with `-c 0`), however this will result in a performance loss of about
|
||||
20%.
|
||||
It is therefore better to compile a specific CMPLOG target with
|
||||
`AFL_LLVM_ONLY_FSRV=1 AFL_LLVM_CMPLOG=1` and pass this binary name via
|
||||
`-c cmplog-fuzzing-target` and compile target again normally with `afl-cc`
|
||||
and use this is the fuzzing target as usual.
|
||||
You can read more about this in
|
||||
[instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md).
|
||||
|
||||
If you use LTO, LLVM, or GCC_PLUGIN mode
|
||||
@ -203,6 +207,9 @@ instances, so running more than one address sanitized target would be a waste.
|
||||
*IF* you are running a saturated corpus, then you can run up to half of the
|
||||
instances with sanitizers.
|
||||
|
||||
An alternative but more effective approach is to use [SAND](./SAND.md) which could
|
||||
combine different sanitizers at a much higher throughput.
|
||||
|
||||
The following sanitizers have built-in support in AFL++:
|
||||
|
||||
* ASAN = Address SANitizer, finds memory corruption vulnerabilities like
|
||||
@ -244,6 +251,12 @@ CFISAN. You might need to experiment which sanitizers you can combine in a
|
||||
target (which means more instances can be run without a sanitized target, which
|
||||
is more effective).
|
||||
|
||||
Note that some sanitizers (MSAN and LSAN) exit with a particular exit code
|
||||
instead of aborting. afl-fuzz treats these exit codes as a crash when these
|
||||
sanitizers are enabled. If the target uses these exit codes there could be false
|
||||
positives among the saved crashes. LSAN uses exit code 23 and MSAN uses exit
|
||||
code 86.
|
||||
|
||||
### d) Modifying the target
|
||||
|
||||
If the target has features that make fuzzing more difficult, e.g., checksums,
|
||||
@ -493,6 +506,8 @@ Note:
|
||||
protection against attacks! So set strong firewall rules and only expose SSH
|
||||
as a network service if you use these (which is highly recommended).
|
||||
|
||||
If you execute afl-fuzz in a Docker container, it is recommended to pass [`--cpuset-cpus`](https://docs.docker.com/engine/containers/resource_constraints/#configure-the-default-cfs-scheduler) option with free CPU cores to docker daemon when starting the container, or pass `AFL_NO_AFFINITY` to afl-fuzz. This is due to the fact that AFL++ will bind to a free CPU core by default, while Docker container will prevent AFL++ instance from seeing processes in other containers or host, which leads to all AFL++ instances trying to bind the same CPU core.
|
||||
|
||||
If you have an input corpus from [step 2](#2-preparing-the-fuzzing-campaign),
|
||||
then specify this directory with the `-i` option. Otherwise, create a new
|
||||
directory and create a file with any content as test data in there.
|
||||
@ -624,8 +639,8 @@ The other secondaries should be run like this:
|
||||
* 40% should run with `-P explore` and 20% with `-P exploit`
|
||||
* If you use `-a` then set 30% of the instances to not use `-a`; if you did
|
||||
not set `-a` (why??), then set 30% to `-a ascii` and 30% to `-a binary`.
|
||||
* run each with a different power schedule, recommended are: `fast` (default),
|
||||
`explore`, `coe`, `lin`, `quad`, `exploit`, and `rare` which you can set with
|
||||
* run each with a different power schedule, recommended are: `explore` (default),
|
||||
`fast`, `coe`, `lin`, `quad`, `exploit`, and `rare` which you can set with
|
||||
the `-p` option, e.g., `-p explore`. See the
|
||||
[FAQ](FAQ.md#what-are-power-schedules) for details.
|
||||
|
||||
@ -854,10 +869,13 @@ Here are some of the most important caveats for AFL++:
|
||||
|
||||
- There is no direct support for fuzzing network services, background daemons,
|
||||
or interactive apps that require UI interaction to work. You may need to make
|
||||
simple code changes to make them behave in a more traditional way. Preeny or
|
||||
libdesock may offer a relatively simple option, too - see:
|
||||
simple code changes to make them behave in a more traditional way. Preeny,
|
||||
libdesock or desockmulti may offer a relatively simple option, too - see:
|
||||
[https://github.com/zardus/preeny](https://github.com/zardus/preeny) or
|
||||
[https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock)
|
||||
[https://github.com/zyingp/desockmulti](https://github.com/zyingp/desockmulti)
|
||||
If these fail then try our own which might be a bit slower but is more
|
||||
reliable: [utils/libaflppdesock](../utils/libaflppdesock)
|
||||
|
||||
Some useful tips for modifying network-based services can be also found at:
|
||||
[https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop)
|
||||
|
29
entitlements.plist
Normal file
29
entitlements.plist
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/ PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>research.com.apple.license-to-operate</key> <true/>
|
||||
<key>application-identifier</key> <string>aflplusplus</string>
|
||||
<key>com.apple.asl.access_as_root</key> <true/>
|
||||
<key>com.apple.backboardd.launchapplications</key> <true/>
|
||||
<key>com.apple.companionappd.connect.allow</key> <true/>
|
||||
<key>com.apple.multitasking.termination</key> <true/>
|
||||
<key>com.apple.private.security.container-required</key> <false/>
|
||||
<key>com.apple.seld.cm</key> <true/>
|
||||
<key>com.apple.sh</key> <true/>
|
||||
<key>com.apple.private.thread-set-state</key> <true/>
|
||||
<key>com.apple.private.cs.debugger</key> <true/>
|
||||
<key>com.apple.springboard.debugapplications</key> <true/>
|
||||
<key>com.apple.springboard.launchapplications</key> <true/>
|
||||
<key>com.apple.springboard.opensensitiveurl</key> <true/>
|
||||
<key>dynamic-codesigning</key> <true/>
|
||||
<key>get-task-allow</key> <true/>
|
||||
<key>platform-application</key> <true/>
|
||||
<key>run-unsigned-code</key> <true/>
|
||||
<key>task_for_pid-allow</key> <true/>
|
||||
<key>com.apple.private.skip-library-validation</key> <true/>
|
||||
<key>com.apple.private.amfi.can-load-cdhash</key> <true/>
|
||||
<key>com.apple.private.amfi.can-execute-cdhash</key> <true/>
|
||||
<key>com.apple.private.security.no-container</key> <true/>
|
||||
</dict>
|
||||
</plist>
|
@ -39,7 +39,7 @@ is *VERY* important to carry out these basic steps first before taking on the
|
||||
additional complexity of debugging with FRIDA mode or `afl-fuzz`.
|
||||
|
||||
- Run your harness outside of the fuzzer, passing it a representative seed as
|
||||
it's input `./harness <input>`.
|
||||
its input `./harness <input>`.
|
||||
- Pass your harness multiple seeds to check that it is stable when running
|
||||
multiple tests as it will when running in fork server mode `./harness <input1>
|
||||
<intput2>`.
|
||||
|
@ -15,15 +15,20 @@ JS_OBJ:=$(BUILD_DIR)api.o
|
||||
SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c)
|
||||
OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src))))
|
||||
|
||||
XTOOLS_HOST?=x86_64-linux-gnu
|
||||
TARGET_CC?=$(CC)
|
||||
TARGET_CXX?=$(CXX)
|
||||
HOST_CC?=$(CC)
|
||||
HOST_CXX?=$(CXX)
|
||||
IS_ANDROID:=$(findstring android, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
IS_x86:=$(findstring i686, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
IS_x86_64:=$(findstring x86_64, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
IS_ARM:=$(findstring arm, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
IS_ARM64:=$(findstring aarch64, $(shell $(TARGET_CC) --version 2>/dev/null))
|
||||
TARGET_CC_INFO=$(shell $(TARGET_CC) --version)
|
||||
IS_IOS:=$(findstring ios, $(TARGET_CC_INFO))
|
||||
IS_SIMULATOR:=$(findstring sim, $(TARGET_CC_INFO))
|
||||
IS_ANDROID:=$(findstring android, $(TARGET_CC_INFO))
|
||||
IS_x86:=$(findstring i686, $(TARGET_CC_INFO))
|
||||
IS_x86_64:=$(findstring x86_64, $(TARGET_CC_INFO))
|
||||
IS_ARM:=$(findstring arm, $(TARGET_CC_INFO))
|
||||
IS_ARM64E:=$(findstring arm64e, $(TARGET_CC_INFO))
|
||||
IS_ARM64 := $(or $(findstring aarch64,$(TARGET_CC_INFO)), $(findstring arm64,$(TARGET_CC_INFO)))
|
||||
CFLAGS+=-fPIC \
|
||||
-D_GNU_SOURCE \
|
||||
-D_FORTIFY_SOURCE=2 \
|
||||
@ -95,7 +100,24 @@ endif
|
||||
|
||||
GUM_ARCH="-$(ARCH)"
|
||||
|
||||
ifeq "$(shell uname)" "Darwin"
|
||||
ifdef IS_IOS
|
||||
OS:=ios
|
||||
ifdef IS_SIMULATOR
|
||||
ifdef IS_x86_64
|
||||
ARCH := x86_64-simulator
|
||||
else ifdef IS_ARM64
|
||||
ARCH := arm64-simulator
|
||||
endif
|
||||
else
|
||||
ifdef IS_ARM64E
|
||||
ARCH := arm64e
|
||||
else ifdef IS_ARM64
|
||||
ARCH := arm64
|
||||
endif
|
||||
endif
|
||||
override CFLAGS += -isysroot $(IOS_SDK_PATH)
|
||||
override LDFLAGS += -L$(IOS_SDK_PATH)/usr/lib
|
||||
else ifeq "$(shell uname)" "Darwin"
|
||||
OS:=macos
|
||||
AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-deprecated-declarations
|
||||
GUM_ARCH:=""
|
||||
@ -165,17 +187,13 @@ ifndef OS
|
||||
$(error "Operating system unsupported")
|
||||
endif
|
||||
|
||||
GUM_DEVKIT_VERSION=16.0.11
|
||||
GUM_DEVKIT_VERSION=17.0.7
|
||||
GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
|
||||
GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
|
||||
|
||||
GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME)
|
||||
ifdef FRIDA_SOURCE
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gumjs-1.0.a
|
||||
else
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
|
||||
endif
|
||||
GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h
|
||||
GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a
|
||||
|
||||
FRIDA_DIR:=$(PWD)build/frida-source/
|
||||
FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile
|
||||
@ -209,13 +227,13 @@ BIN2C_SRC:=$(PWD)util/bin2c.c
|
||||
all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN)
|
||||
|
||||
32:
|
||||
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
XTOOLS_HOST=i686-linux-gnu CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
|
||||
|
||||
arm:
|
||||
CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
|
||||
XTOOLS_HOST=arm-linux-gnueabihf CFLAGS="-marm" LDFLAGS="-marm" ARCH="armhf" TARGET_CC=arm-linux-gnueabihf-gcc TARGET_CXX=arm-linux-gnueabihf-g++ make all
|
||||
|
||||
arm64:
|
||||
ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
|
||||
XTOOLS_HOST=aarch64-linux-gnu ARCH="arm64" TARGET_CC=aarch64-linux-gnu-gcc TARGET_CXX=aarch64-linux-gnu-g++ make all
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
@ -228,114 +246,29 @@ $(OBJ_DIR): | $(BUILD_DIR)
|
||||
$(FRIDA_BUILD_DIR): | $(BUILD_DIR)
|
||||
mkdir -p $@
|
||||
|
||||
#TODO Set architecture
|
||||
ifdef FRIDA_SOURCE
|
||||
$(FRIDA_MAKEFILE): | $(BUILD_DIR)
|
||||
git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR)
|
||||
git clone https://github.com/frida/frida-gum.git $(FRIDA_DIR)
|
||||
cd $(FRIDA_DIR) && \
|
||||
./configure \
|
||||
--host=$(XTOOLS_HOST) \
|
||||
--enable-tests \
|
||||
--enable-gumpp \
|
||||
--enable-gumjs \
|
||||
--with-devkits=gum,gumjs
|
||||
|
||||
.PHONY: $(GUM_DEVIT_LIBRARY)
|
||||
|
||||
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE)
|
||||
cd $(FRIDA_DIR) && make gum-$(OS)$(GUM_ARCH) FRIDA_V8=disabled
|
||||
|
||||
$(GUM_DEVIT_HEADER): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
|
||||
echo "#include <stdio.h>" > $@
|
||||
echo "#include <unistd.h>" >> $@
|
||||
echo "#include <gum/gumreturnaddress.h>" >> $@
|
||||
echo "#include <gum/gumbacktracer.h>" >> $@
|
||||
echo "#include <gum/gumsymbolutil.h>" >> $@
|
||||
echo "#include <gum/gumstalker.h>" >> $@
|
||||
echo "#include <gum/gumlibc.h>" >> $@
|
||||
echo "#include <gumjs/gumscriptbackend.h>" >> $@
|
||||
|
||||
ifeq "$(OS)" "macos"
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libiconv.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libv8-8.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgmodule-2.0.a \
|
||||
|
||||
else ifeq "$(ARCH)" "arm64"
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
$(GUM_DEVIT_LIBRARY): $(FRIDA_MAKEFILE) | $(FRIDA_BUILD_DIR)
|
||||
echo $(GUM_DEVIT_LIBRARY) $(FRIDA_MAKEFILE) $(FRIDA_BUILD_DIR)
|
||||
cd $(FRIDA_DIR) && make FRIDA_V8=disabled
|
||||
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/frida-gumjs.h $(GUM_DEVIT_HEADER)
|
||||
cp $(FRIDA_DIR)build/bindings/gumjs/devkit/libfrida-gumjs.a $(GUM_DEVIT_LIBRARY)
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
else
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \
|
||||
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \
|
||||
-I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/
|
||||
|
||||
ifeq "$(OS)" "android"
|
||||
CFLAGS += -static-libstdc++
|
||||
endif
|
||||
|
||||
TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libtcc.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libjson-glib-1.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libquickjs.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libcapstone.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libunwind.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libffi.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libdwarf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libelf.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgio-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libgobject-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libglib-2.0.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \
|
||||
$(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \
|
||||
|
||||
|
||||
else
|
||||
$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR)
|
||||
@ -373,6 +306,11 @@ $(AFL_PERFORMANCE_OBJ): $(AFL_PERFORMANCE_SRC)
|
||||
|
||||
$(BIN2C): $(BIN2C_SRC)
|
||||
$(HOST_CC) -D_GNU_SOURCE -o $@ $<
|
||||
ifdef IS_IOS
|
||||
ifeq ($(HOST_CC),$(TARGET_CC))
|
||||
@ldid -S../entitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
endif
|
||||
|
||||
$(JS_SRC): $(JS) $(BIN2C)| $(BUILD_DIR)
|
||||
cd $(JS_DIR) && $(BIN2C) api_js $(JS) $@
|
||||
@ -413,8 +351,10 @@ $(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL
|
||||
$(TRACE_LDFLAGS) \
|
||||
$(LDFLAGS) \
|
||||
$(LDSCRIPT) \
|
||||
-o $@ \
|
||||
|
||||
-o $@
|
||||
ifdef IS_IOS
|
||||
@ldid -S../entitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
cp -v $(FRIDA_TRACE) $(ROOT)
|
||||
|
||||
$(FRIDA_TRACE_LIB): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL_COMPILER_RT_OBJ) $(AFL_PERFORMANCE_OBJ) GNUmakefile | $(BUILD_DIR)
|
||||
@ -430,9 +370,15 @@ $(FRIDA_TRACE_LIB): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $
|
||||
|
||||
$(AFLPP_FRIDA_DRIVER_HOOK_OBJ): $(AFLPP_FRIDA_DRIVER_HOOK_SRC) $(GUM_DEVIT_HEADER) | $(BUILD_DIR)
|
||||
$(TARGET_CC) $(CFLAGS) $(LDFLAGS) -I $(FRIDA_BUILD_DIR) $< -o $@
|
||||
ifdef IS_IOS
|
||||
@ldid -S../entitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
$(AFLPP_QEMU_DRIVER_HOOK_OBJ): $(AFLPP_QEMU_DRIVER_HOOK_SRC) | $(BUILD_DIR)
|
||||
$(TARGET_CC) $(CFLAGS) $(LDFLAGS) $< -o $@
|
||||
ifdef IS_IOS
|
||||
@ldid -S../entitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; }
|
||||
endif
|
||||
|
||||
hook: $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ)
|
||||
|
||||
|
@ -107,7 +107,7 @@ every block of code we execute, performance is critical.
|
||||
However, the design of the binary instrumentation modes of AFL++ has moved on.
|
||||
Both QEMU and FRIDA modes use a two stage process when executing a target
|
||||
application. Each block is first compiled or instrumented, and then it is
|
||||
executed. The compiled blocks can be re-used each time the target executes them.
|
||||
executed. The compiled blocks can be reused each time the target executes them.
|
||||
|
||||
Since a blocks ID is based on its address, and this is known at compile time, we
|
||||
only need to generate this ID once per block and so this ID generation no longer
|
||||
|
@ -200,10 +200,10 @@ instrumented address block translations.
|
||||
* `AFL_FRIDA_INST_NO_SUPPRESS` - Disable deterministic branch suppression.
|
||||
Deterministic branch suppression skips the preamble which generates coverage
|
||||
information at the start of each block, if the block is reached by a
|
||||
deterministic branch. This reduces map polution, and may improve performance
|
||||
deterministic branch. This reduces map pollution, and may improve performance
|
||||
when all the executing blocks have been prefetched and backpatching applied.
|
||||
However, in the event that backpatching is incomplete, this may incur a
|
||||
performance penatly as branch instructions are disassembled on each branch.
|
||||
performance penalty as branch instructions are disassembled on each branch.
|
||||
* `AFL_FRIDA_INST_SEED` - Sets the initial seed for the hash function used to
|
||||
generate block (and hence edge) IDs. Setting this to a constant value may be
|
||||
useful for debugging purposes, e.g., investigating unstable edges.
|
||||
@ -215,7 +215,7 @@ instrumented address block translations.
|
||||
coverage information for unstable edges (e.g., to be loaded within IDA
|
||||
lighthouse).
|
||||
* `AFL_FRIDA_JS_SCRIPT` - Set the script to be loaded by the FRIDA scripting
|
||||
engine. See [Scipting.md](Scripting.md) for details.
|
||||
engine. See [Scripting.md](Scripting.md) for details.
|
||||
* `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target
|
||||
application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`).
|
||||
* `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target
|
||||
|
@ -724,16 +724,16 @@ class Afl {
|
||||
* it takes as arguments a `NativePointer` and a `number`. It can be
|
||||
* called multiple times to exclude several ranges.
|
||||
*/
|
||||
static addExcludedRange(addressess, size) {
|
||||
Afl.jsApiAddExcludeRange(addressess, size);
|
||||
static addExcludedRange(addresses, size) {
|
||||
Afl.jsApiAddExcludeRange(addresses, size);
|
||||
}
|
||||
/**
|
||||
* This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`,
|
||||
* it takes as arguments a `NativePointer` and a `number`. It can be
|
||||
* called multiple times to include several ranges.
|
||||
*/
|
||||
static addIncludedRange(addressess, size) {
|
||||
Afl.jsApiAddIncludeRange(addressess, size);
|
||||
static addIncludedRange(addresses, size) {
|
||||
Afl.jsApiAddIncludeRange(addresses, size);
|
||||
}
|
||||
/**
|
||||
* This must always be called at the end of your script. This lets
|
||||
@ -771,7 +771,7 @@ class Afl {
|
||||
}
|
||||
/**
|
||||
* Print a message to the STDOUT. This should be preferred to
|
||||
* FRIDA's `console.log` since FRIDA will queue it's log messages.
|
||||
* FRIDA's `console.log` since FRIDA will queue its log messages.
|
||||
* If `console.log` is used in a callback in particular, then there
|
||||
* may no longer be a thread running to service this queue.
|
||||
*/
|
||||
@ -893,14 +893,14 @@ class Afl {
|
||||
}
|
||||
/**
|
||||
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
|
||||
* `NativePointer` should be provided as it's argument.
|
||||
* `NativePointer` should be provided as its argument.
|
||||
*/
|
||||
static setPersistentAddress(address) {
|
||||
Afl.jsApiSetPersistentAddress(address);
|
||||
}
|
||||
/**
|
||||
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
|
||||
* `number` should be provided as it's argument.
|
||||
* `number` should be provided as its argument.
|
||||
*/
|
||||
static setPersistentCount(count) {
|
||||
Afl.jsApiSetPersistentCount(count);
|
||||
@ -920,7 +920,7 @@ class Afl {
|
||||
}
|
||||
/**
|
||||
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
|
||||
* `NativePointer` should be provided as it's argument.
|
||||
* `NativePointer` should be provided as its argument.
|
||||
*/
|
||||
static setPersistentReturn(address) {
|
||||
Afl.jsApiSetPersistentReturn(address);
|
||||
|
@ -4,6 +4,6 @@ This folder contains a Docker image to allow the building of
|
||||
`afl-frida-trace.so` using the `many-linux` docker image. This docker image is
|
||||
based on CentOS Linux 5. By building `afl-frida-trace.so` for such an old
|
||||
version of Linux, given the strong backward compatibility of Linux, this should
|
||||
work on the majority of Linux environments. This may be useful for targetting
|
||||
work on the majority of Linux environments. This may be useful for targeting
|
||||
Linux distributions other than your development environment. `many-local` builds
|
||||
`AFLplusplus` from the local working copy in the `many-linux` environment.
|
||||
|
@ -27,25 +27,21 @@ void asan_init(void) {
|
||||
|
||||
}
|
||||
|
||||
static gboolean asan_exclude_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
static gboolean asan_exclude_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
gchar *symbol_name = (gchar *)user_data;
|
||||
GumAddress address;
|
||||
gchar *symbol_name = (gchar *)user_data;
|
||||
GumAddress address;
|
||||
const GumMemoryRange *range = gum_module_get_range(module);
|
||||
|
||||
address = gum_module_find_export_by_name(details->name, symbol_name);
|
||||
address = gum_module_find_export_by_name(module, symbol_name);
|
||||
if (address == 0) { return TRUE; }
|
||||
|
||||
/* If the reported address of the symbol is outside of the range of the module
|
||||
* then ignore it */
|
||||
if (address < details->range->base_address) { return TRUE; }
|
||||
if (address > (details->range->base_address + details->range->size)) {
|
||||
if (address < range->base_address) { return TRUE; }
|
||||
if (address > (range->base_address + range->size)) { return TRUE; }
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
ranges_add_exclude((GumMemoryRange *)details->range);
|
||||
ranges_add_exclude((GumMemoryRange *)range);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ gboolean cmplog_is_readable(guint64 addr, size_t size) {
|
||||
*/
|
||||
if (addr < DEFAULT_MMAP_MIN_ADDR) { return false; }
|
||||
|
||||
/* Check our addres/length don't wrap around */
|
||||
/* Check our address/length don't wrap around */
|
||||
if (SIZE_MAX - addr < size) { return false; }
|
||||
|
||||
GumAddress inner_base = addr;
|
||||
|
@ -186,7 +186,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
|
||||
* execution), we instead ensure that we honour the additional
|
||||
* instrumentation requested (e.g. coverage, asan and complog) when a block
|
||||
* is compiled no matter where we are during initialization. We will end up
|
||||
* re-using these blocks if the code under test calls a block which is also
|
||||
* reusing these blocks if the code under test calls a block which is also
|
||||
* used during initialization.
|
||||
*
|
||||
* Coverage data generated during initialization isn't a problem since the
|
||||
|
@ -285,7 +285,7 @@ static void instrument_coverage_switch(GumStalkerObserver *self,
|
||||
|
||||
/*
|
||||
* If the branch is deterministic, then we should start execution at the
|
||||
* begining of the block. From here, we will branch and skip the coverage
|
||||
* beginning of the block. From here, we will branch and skip the coverage
|
||||
* code and jump right to the target code of the instrumented block.
|
||||
* Otherwise, if the branch is non-deterministic, then we need to branch
|
||||
* part way into the block to where the coverage instrumentation starts.
|
||||
@ -516,7 +516,7 @@ void instrument_coverage_optimize(const cs_insn *instr,
|
||||
* an instruction to load x16,x17 from beyond the red-zone on the stack. A
|
||||
* pair of registers are saved/restored because on AARCH64, the stack pointer
|
||||
* must be 16 byte aligned. This instruction is emitted into the block before
|
||||
* the tranformer (from which we are called) is executed. If is is possible
|
||||
* the transformer (from which we are called) is executed. If is is possible
|
||||
* for Stalker to make a direct branch (the target block is close enough), it
|
||||
* can forego pushing the registers and instead branch at an offset into the
|
||||
* block to skip this restoration prolog.
|
||||
|
@ -5,16 +5,16 @@ class Afl {
|
||||
* it takes as arguments a `NativePointer` and a `number`. It can be
|
||||
* called multiple times to exclude several ranges.
|
||||
*/
|
||||
static addExcludedRange(addressess, size) {
|
||||
Afl.jsApiAddExcludeRange(addressess, size);
|
||||
static addExcludedRange(addresses, size) {
|
||||
Afl.jsApiAddExcludeRange(addresses, size);
|
||||
}
|
||||
/**
|
||||
* This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`,
|
||||
* it takes as arguments a `NativePointer` and a `number`. It can be
|
||||
* called multiple times to include several ranges.
|
||||
*/
|
||||
static addIncludedRange(addressess, size) {
|
||||
Afl.jsApiAddIncludeRange(addressess, size);
|
||||
static addIncludedRange(addresses, size) {
|
||||
Afl.jsApiAddIncludeRange(addresses, size);
|
||||
}
|
||||
/**
|
||||
* This must always be called at the end of your script. This lets
|
||||
@ -52,7 +52,7 @@ class Afl {
|
||||
}
|
||||
/**
|
||||
* Print a message to the STDOUT. This should be preferred to
|
||||
* FRIDA's `console.log` since FRIDA will queue it's log messages.
|
||||
* FRIDA's `console.log` since FRIDA will queue its log messages.
|
||||
* If `console.log` is used in a callback in particular, then there
|
||||
* may no longer be a thread running to service this queue.
|
||||
*/
|
||||
@ -205,14 +205,14 @@ class Afl {
|
||||
}
|
||||
/**
|
||||
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
|
||||
* `NativePointer` should be provided as it's argument.
|
||||
* `NativePointer` should be provided as its argument.
|
||||
*/
|
||||
static setPersistentAddress(address) {
|
||||
Afl.jsApiSetPersistentAddress(address);
|
||||
}
|
||||
/**
|
||||
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
|
||||
* `number` should be provided as it's argument.
|
||||
* `number` should be provided as its argument.
|
||||
*/
|
||||
static setPersistentCount(count) {
|
||||
Afl.jsApiSetPersistentCount(count);
|
||||
@ -232,7 +232,7 @@ class Afl {
|
||||
}
|
||||
/**
|
||||
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
|
||||
* `NativePointer` should be provided as it's argument.
|
||||
* `NativePointer` should be provided as its argument.
|
||||
*/
|
||||
static setPersistentReturn(address) {
|
||||
Afl.jsApiSetPersistentReturn(address);
|
||||
@ -382,5 +382,5 @@ Afl.jsApiSetTraceable = Afl.jsApiGetFunction("js_api_set_traceable", "void", [])
|
||||
Afl.jsApiSetVerbose = Afl.jsApiGetFunction("js_api_set_verbose", "void", []);
|
||||
Afl.jsApiWrite = new NativeFunction(
|
||||
/* tslint:disable-next-line:no-null-keyword */
|
||||
Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]);
|
||||
Module.getGlobalExportByName("write"), "int", ["int", "pointer", "int"]);
|
||||
Afl.jsApiIjonSet = Afl.jsApiGetFunction("js_api_ijon_set", "void", ["uint32"]);
|
||||
|
@ -39,17 +39,19 @@ typedef struct {
|
||||
static guint64 text_base = 0;
|
||||
static guint64 text_limit = 0;
|
||||
|
||||
static gboolean lib_find_exe(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
static gboolean lib_find_exe(GumModule *module, gpointer user_data) {
|
||||
|
||||
lib_details_t *lib_details = (lib_details_t *)user_data;
|
||||
lib_details_t *lib_details = (lib_details_t *)user_data;
|
||||
const gchar *name = gum_module_get_name(module);
|
||||
const gchar *path = gum_module_get_path(module);
|
||||
const GumMemoryRange *range = gum_module_get_range(module);
|
||||
|
||||
strncpy(lib_details->name, details->name, PATH_MAX);
|
||||
strncpy(lib_details->path, details->path, PATH_MAX);
|
||||
strncpy(lib_details->name, name, PATH_MAX);
|
||||
strncpy(lib_details->path, path, PATH_MAX);
|
||||
lib_details->name[PATH_MAX] = '\0';
|
||||
lib_details->path[PATH_MAX] = '\0';
|
||||
lib_details->base_address = details->range->base_address;
|
||||
lib_details->size = details->range->size;
|
||||
lib_details->base_address = range->base_address;
|
||||
lib_details->size = range->size;
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
@ -12,17 +12,18 @@ extern void gum_darwin_enumerate_modules(mach_port_t task,
|
||||
static guint64 text_base = 0;
|
||||
static guint64 text_limit = 0;
|
||||
|
||||
static gboolean lib_get_main_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
static gboolean lib_get_main_module(GumModule *module, gpointer user_data) {
|
||||
|
||||
GumDarwinModule **ret = (GumDarwinModule **)user_data;
|
||||
GumDarwinModule *module = gum_darwin_module_new_from_memory(
|
||||
details->path, mach_task_self(), details->range->base_address,
|
||||
GUM_DARWIN_MODULE_FLAGS_NONE, NULL);
|
||||
GumDarwinModule **ret = (GumDarwinModule **)user_data;
|
||||
const gchar *path = gum_module_get_path(module);
|
||||
const GumMemoryRange *range = gum_module_get_range(module);
|
||||
GumDarwinModule *darwin_module = gum_darwin_module_new_from_memory(
|
||||
path, mach_task_self(), range->base_address, GUM_DARWIN_MODULE_FLAGS_NONE,
|
||||
NULL);
|
||||
|
||||
FVERBOSE("Found main module: %s", module->name);
|
||||
FVERBOSE("Found main module: %s", darwin_module->name);
|
||||
|
||||
*ret = module;
|
||||
*ret = darwin_module;
|
||||
|
||||
return FALSE;
|
||||
|
||||
|
@ -46,6 +46,7 @@ gboolean found_range(const GumRangeDetails *details, gpointer user_data) {
|
||||
static int on_dlclose(void *handle) {
|
||||
|
||||
GArray *ranges = NULL;
|
||||
GumModule *module = NULL;
|
||||
struct link_map *lm = NULL;
|
||||
gum_range_t *range = NULL;
|
||||
GumAddress base;
|
||||
@ -61,8 +62,12 @@ static int on_dlclose(void *handle) {
|
||||
FVERBOSE("on_dlclose: %s", lm->l_name);
|
||||
|
||||
ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t));
|
||||
gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range,
|
||||
ranges);
|
||||
|
||||
module = gum_process_find_module_by_name(lm->l_name);
|
||||
|
||||
if (module == NULL) { FATAL("Failed to find module: %s", lm->l_name); }
|
||||
|
||||
gum_module_enumerate_ranges(module, GUM_PAGE_EXECUTE, found_range, ranges);
|
||||
|
||||
int ret = dlclose(handle);
|
||||
if (ret != 0) {
|
||||
|
@ -295,6 +295,8 @@ void persistent_prologue_arch(GumStalkerOutput *output) {
|
||||
* CALL instrument_afl_persistent_loop
|
||||
* CALL hook (optionally)
|
||||
* RESTORE REGS
|
||||
* CALL INSTRUMENTED PERSISTENT FUNC
|
||||
* JMP loop
|
||||
* INSTRUMENTED PERSISTENT FUNC
|
||||
*/
|
||||
|
||||
@ -302,15 +304,25 @@ void persistent_prologue_arch(GumStalkerOutput *output) {
|
||||
|
||||
FVERBOSE("Persistent loop reached");
|
||||
|
||||
/* This is the location our epilogue should be written below */
|
||||
if (persistent_ret == 0) { instrument_persitent_save_lr(cw); }
|
||||
|
||||
/* Save the current context */
|
||||
instrument_persitent_save_regs(cw, &saved_regs);
|
||||
|
||||
/* Store a pointer to where we should return for our next iteration */
|
||||
/*
|
||||
* Store a pointer to where we should return for our next iteration.
|
||||
* This is the location our epilogue should branch to
|
||||
*/
|
||||
persistent_loop = gum_arm64_writer_cur(cw);
|
||||
|
||||
/* call __afl_persistent_loop and _exit if zero. Also reset our previous_pc */
|
||||
gconstpointer loop = cw->code + 1;
|
||||
gum_arm64_writer_put_label(cw, loop);
|
||||
|
||||
/*
|
||||
* call __afl_persistent_loop which will _exit if we have reached our
|
||||
* loop count. Also reset our previous_pc
|
||||
*/
|
||||
instrument_afl_persistent_loop(cw);
|
||||
|
||||
/* Optionally call the persistent hook */
|
||||
@ -319,6 +331,27 @@ void persistent_prologue_arch(GumStalkerOutput *output) {
|
||||
/* Restore our CPU context before we continue execution */
|
||||
instrument_persitent_restore_regs(cw, &saved_regs);
|
||||
|
||||
gconstpointer original = cw->code + 1;
|
||||
|
||||
/*
|
||||
* Call our original code, that way we regain control if our target
|
||||
* function returns without reaching the epilogue as an additional
|
||||
* safety net
|
||||
*/
|
||||
gum_arm64_writer_put_bl_label(cw, original);
|
||||
|
||||
/*
|
||||
* Return for our next iteration if our original function returns
|
||||
* and control hasn't reached the epilogue for some reason
|
||||
*/
|
||||
gum_arm64_writer_put_b_label(cw, loop);
|
||||
|
||||
/*
|
||||
* The original code for our target function will be emitted
|
||||
* immediately following this
|
||||
*/
|
||||
gum_arm64_writer_put_label(cw, original);
|
||||
|
||||
if (persistent_debug) { gum_arm64_writer_put_brk_imm(cw, 0); }
|
||||
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ static int prefetch_on_fork(void) {
|
||||
static void prefetch_hook_fork(void) {
|
||||
|
||||
void *fork_addr =
|
||||
GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork"));
|
||||
GSIZE_TO_POINTER(gum_module_find_global_export_by_name("fork"));
|
||||
intercept_hook(fork_addr, prefetch_on_fork, NULL);
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ static void convert_address_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
if (token_count != 2) {
|
||||
|
||||
FFATAL("Invalid range (should have two addresses seperated by a '-'): %s\n",
|
||||
FFATAL("Invalid range (should have two addresses separated by a '-'): %s\n",
|
||||
token);
|
||||
|
||||
}
|
||||
@ -116,20 +116,22 @@ static void convert_address_token(gchar *token, GumMemoryRange *range) {
|
||||
|
||||
}
|
||||
|
||||
static gboolean convert_name_token_for_module(const GumModuleDetails *details,
|
||||
gpointer user_data) {
|
||||
static gboolean convert_name_token_for_module(GumModule *module,
|
||||
gpointer user_data) {
|
||||
|
||||
convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data;
|
||||
if (details->path == NULL) { return true; };
|
||||
convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data;
|
||||
const GumMemoryRange *range = gum_module_get_range(module);
|
||||
const gchar *path = gum_module_get_path(module);
|
||||
if (path == NULL) { return true; };
|
||||
|
||||
if (!g_str_has_suffix(details->path, ctx->suffix)) { return true; };
|
||||
if (!g_str_has_suffix(path, ctx->suffix)) { return true; };
|
||||
|
||||
FVERBOSE("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER
|
||||
"x-0x%016" G_GINT64_MODIFIER "x %s",
|
||||
ctx->suffix, details->range->base_address,
|
||||
details->range->base_address + details->range->size, details->path);
|
||||
ctx->suffix, range->base_address, range->base_address + range->size,
|
||||
path);
|
||||
|
||||
*ctx->range = *details->range;
|
||||
*ctx->range = *range;
|
||||
ctx->done = true;
|
||||
return false;
|
||||
|
||||
|
@ -11,8 +11,8 @@ class Afl {
|
||||
* it takes as arguments a `NativePointer` and a `number`. It can be
|
||||
* called multiple times to exclude several ranges.
|
||||
*/
|
||||
public static addExcludedRange(addressess: NativePointer, size: number): void {
|
||||
Afl.jsApiAddExcludeRange(addressess, size);
|
||||
public static addExcludedRange(addresses: NativePointer, size: number): void {
|
||||
Afl.jsApiAddExcludeRange(addresses, size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -20,8 +20,8 @@ class Afl {
|
||||
* it takes as arguments a `NativePointer` and a `number`. It can be
|
||||
* called multiple times to include several ranges.
|
||||
*/
|
||||
public static addIncludedRange(addressess: NativePointer, size: number): void {
|
||||
Afl.jsApiAddIncludeRange(addressess, size);
|
||||
public static addIncludedRange(addresses: NativePointer, size: number): void {
|
||||
Afl.jsApiAddIncludeRange(addresses, size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,7 +66,7 @@ class Afl {
|
||||
|
||||
/**
|
||||
* Print a message to the STDOUT. This should be preferred to
|
||||
* FRIDA's `console.log` since FRIDA will queue it's log messages.
|
||||
* FRIDA's `console.log` since FRIDA will queue its log messages.
|
||||
* If `console.log` is used in a callback in particular, then there
|
||||
* may no longer be a thread running to service this queue.
|
||||
*/
|
||||
@ -241,7 +241,7 @@ class Afl {
|
||||
|
||||
/**
|
||||
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
|
||||
* `NativePointer` should be provided as it's argument.
|
||||
* `NativePointer` should be provided as its argument.
|
||||
*/
|
||||
public static setPersistentAddress(address: NativePointer): void {
|
||||
Afl.jsApiSetPersistentAddress(address);
|
||||
@ -249,7 +249,7 @@ class Afl {
|
||||
|
||||
/**
|
||||
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
|
||||
* `number` should be provided as it's argument.
|
||||
* `number` should be provided as its argument.
|
||||
*/
|
||||
public static setPersistentCount(count: number): void {
|
||||
Afl.jsApiSetPersistentCount(count);
|
||||
@ -272,7 +272,7 @@ class Afl {
|
||||
|
||||
/**
|
||||
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
|
||||
* `NativePointer` should be provided as it's argument.
|
||||
* `NativePointer` should be provided as its argument.
|
||||
*/
|
||||
public static setPersistentReturn(address: NativePointer): void {
|
||||
Afl.jsApiSetPersistentReturn(address);
|
||||
|
@ -9,5 +9,11 @@ echo Newest available version: $NEW
|
||||
|
||||
test -z "$OLD" -o -z "$NEW" -o "$OLD" = "$NEW" && { echo Nothing to be done. ; exit 0 ; }
|
||||
|
||||
sed -i "s/=$OLD/=$NEW/" GNUmakefile || exit 1
|
||||
# Determine the correct sed command
|
||||
case $(sed --help 2>&1) in
|
||||
*GNU*) set sed -i;;
|
||||
*) set sed -i '';;
|
||||
esac
|
||||
|
||||
"$@" "s/=$OLD/=$NEW/" GNUmakefile || exit 1
|
||||
echo Successfully updated GNUmakefile
|
||||
|
@ -75,6 +75,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include "asanfuzz.h"
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__) || defined(__DragonFly__)
|
||||
@ -352,6 +353,8 @@ enum {
|
||||
|
||||
};
|
||||
|
||||
#define FAST_RESUME_VERSION 0x01000000
|
||||
|
||||
/* Python stuff */
|
||||
#ifdef USE_PYTHON
|
||||
|
||||
@ -459,7 +462,10 @@ typedef struct afl_env_vars {
|
||||
afl_no_startup_calibration, afl_no_warn_instability,
|
||||
afl_post_process_keep_original, afl_crashing_seeds_as_new_crash,
|
||||
afl_final_sync, afl_ignore_seed_problems, afl_disable_redundant,
|
||||
afl_sha1_filenames, afl_no_sync, afl_no_fastresume;
|
||||
afl_sha1_filenames, afl_no_sync, afl_no_fastresume, afl_forksrv_uid_set,
|
||||
afl_forksrv_gid_set;
|
||||
|
||||
u16 afl_forksrv_nb_supl_gids;
|
||||
|
||||
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
|
||||
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
|
||||
@ -470,6 +476,12 @@ typedef struct afl_env_vars {
|
||||
|
||||
s32 afl_pizza_mode;
|
||||
|
||||
uid_t afl_forksrv_uid;
|
||||
|
||||
gid_t afl_forksrv_gid;
|
||||
|
||||
gid_t *afl_forksrv_supl_gids;
|
||||
|
||||
} afl_env_vars_t;
|
||||
|
||||
struct afl_pass_stat {
|
||||
@ -552,6 +564,10 @@ typedef struct afl_state {
|
||||
*orig_cmdline, /* Original command line */
|
||||
*infoexec; /* Command to execute on a new crash */
|
||||
|
||||
mode_t perm, /* File permission when creating files */
|
||||
dir_perm; /* File permission when creating directories */
|
||||
u8 chown_needed; /* Group owner of files needs to be modified */
|
||||
|
||||
u32 hang_tmout, /* Timeout used for hang det (ms) */
|
||||
stats_update_freq; /* Stats update frequency (execs) */
|
||||
|
||||
@ -610,7 +626,11 @@ typedef struct afl_state {
|
||||
u8 *var_bytes; /* Bytes that appear to be variable */
|
||||
|
||||
#define N_FUZZ_SIZE (1 << 21)
|
||||
#define N_FUZZ_SIZE_BITMAP (1 << 29)
|
||||
u32 *n_fuzz;
|
||||
u8 *n_fuzz_dup;
|
||||
u8 *classified_n_fuzz;
|
||||
u8 *simplified_n_fuzz;
|
||||
|
||||
volatile u8 stop_soon, /* Ctrl-C pressed? */
|
||||
clear_screen; /* Window resized? */
|
||||
@ -714,6 +734,8 @@ typedef struct afl_state {
|
||||
|
||||
struct queue_entry **top_rated; /* Top entries for bitmap bytes */
|
||||
|
||||
u32 **top_rated_candidates; /* Candidate IDs per bitmap index */
|
||||
|
||||
struct extra_data *extras; /* Extra tokens to fuzz with */
|
||||
u32 extras_cnt; /* Total number of tokens read */
|
||||
|
||||
@ -728,6 +750,13 @@ typedef struct afl_state {
|
||||
char *cmplog_binary;
|
||||
afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */
|
||||
|
||||
/* ASAN Fuzing */
|
||||
char *san_binary[MAX_EXTRA_SAN_BINARY];
|
||||
afl_forkserver_t san_fsrvs[MAX_EXTRA_SAN_BINARY];
|
||||
u8 san_binary_length; /* 0 means extra san binaries not given */
|
||||
u32 san_case_status;
|
||||
enum SanitizerAbstraction san_abstraction;
|
||||
|
||||
/* Custom mutators */
|
||||
struct custom_mutator *mutator;
|
||||
|
||||
@ -747,13 +776,14 @@ typedef struct afl_state {
|
||||
up to 256 */
|
||||
|
||||
unsigned long long int last_avg_exec_update;
|
||||
u32 last_avg_execs;
|
||||
u64 last_avg_total_execs;
|
||||
double last_avg_execs_saved;
|
||||
|
||||
/* foreign sync */
|
||||
#define FOREIGN_SYNCS_MAX 32U
|
||||
u8 foreign_sync_cnt;
|
||||
struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
|
||||
char *foreign_file;
|
||||
|
||||
#ifdef _AFL_DOCUMENT_MUTATIONS
|
||||
u8 do_document;
|
||||
@ -848,6 +878,8 @@ typedef struct afl_state {
|
||||
|
||||
struct skipdet_global *skipdet_g;
|
||||
|
||||
s64 last_scored_idx; /* Index of the last queue entry re-scored */
|
||||
|
||||
#ifdef INTROSPECTION
|
||||
char mutation[8072];
|
||||
char m_tmp[4096];
|
||||
@ -908,7 +940,7 @@ struct custom_mutator {
|
||||
/**
|
||||
* Opt-out of a splicing input for the fuzz mutator
|
||||
*
|
||||
* Empty dummy function. It's presence tells afl-fuzz not to pass a
|
||||
* Empty dummy function. Its presence tells afl-fuzz not to pass a
|
||||
* splice data pointer and len.
|
||||
*
|
||||
* @param data pointer returned in afl_custom_init by this custom mutator
|
||||
@ -940,12 +972,12 @@ struct custom_mutator {
|
||||
/**
|
||||
* Describe the current testcase, generated by the last mutation.
|
||||
* This will be called, for example, to give the written testcase a name
|
||||
* after a crash ocurred. It can help to reproduce crashing mutations.
|
||||
* after a crash occurred. It can help to reproduce crashing mutations.
|
||||
*
|
||||
* (Optional)
|
||||
*
|
||||
* @param data pointer returned by afl_customm_init for this custom mutator
|
||||
* @paramp[in] max_description_len maximum size avaliable for the description.
|
||||
* @paramp[in] max_description_len maximum size available for the description.
|
||||
* A longer return string is legal, but will be truncated.
|
||||
* @return A valid ptr to a 0-terminated string.
|
||||
* An empty or NULL return will result in a default description
|
||||
@ -1121,8 +1153,9 @@ struct custom_mutator {
|
||||
|
||||
void afl_state_init(afl_state_t *, uint32_t map_size);
|
||||
void afl_state_deinit(afl_state_t *);
|
||||
void afl_resize_map_buffers(afl_state_t *, u32 old_size, u32 new_size);
|
||||
|
||||
/* Set stop_soon flag on all childs, kill all childs */
|
||||
/* Set stop_soon flag on all children, kill all children */
|
||||
void afl_states_stop(void);
|
||||
/* Set clear_screen flag on all states */
|
||||
void afl_states_clear_screen(void);
|
||||
@ -1162,7 +1195,7 @@ u8 havoc_mutation_probability_py(void *);
|
||||
u8 queue_get_py(void *, const u8 *);
|
||||
const char *introspection_py(void *);
|
||||
u8 queue_new_entry_py(void *, const u8 *, const u8 *);
|
||||
void splice_optout(void *);
|
||||
void splice_optout_py(void *);
|
||||
void deinit_py(void *);
|
||||
|
||||
#endif
|
||||
@ -1170,13 +1203,13 @@ void deinit_py(void *);
|
||||
/* Queue */
|
||||
|
||||
void mark_as_det_done(afl_state_t *, struct queue_entry *);
|
||||
void mark_as_variable(afl_state_t *, struct queue_entry *);
|
||||
void mark_as_redundant(afl_state_t *, struct queue_entry *, u8);
|
||||
void add_to_queue(afl_state_t *, u8 *, u32, u8);
|
||||
void destroy_queue(afl_state_t *);
|
||||
void update_bitmap_score(afl_state_t *, struct queue_entry *);
|
||||
void update_bitmap_score(afl_state_t *, struct queue_entry *, bool);
|
||||
void cull_queue(afl_state_t *);
|
||||
u32 calculate_score(afl_state_t *, struct queue_entry *);
|
||||
void recalculate_all_scores(afl_state_t *);
|
||||
void update_bitmap_rescore(afl_state_t *, struct queue_entry *, u32);
|
||||
|
||||
/* Bitmap */
|
||||
|
||||
@ -1197,7 +1230,6 @@ u8 *describe_op(afl_state_t *, u8, size_t);
|
||||
#endif
|
||||
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
|
||||
u8 has_new_bits(afl_state_t *, u8 *);
|
||||
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
|
||||
#ifndef AFL_SHOWMAP
|
||||
void classify_counts(afl_forkserver_t *);
|
||||
#endif
|
||||
@ -1240,6 +1272,7 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen);
|
||||
|
||||
/* Run */
|
||||
|
||||
void check_sync_fuzzers(afl_state_t *);
|
||||
void sync_fuzzers(afl_state_t *);
|
||||
u32 write_to_testcase(afl_state_t *, void **, u32, u32);
|
||||
u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
|
||||
@ -1260,7 +1293,6 @@ u8 fuzz_one(afl_state_t *);
|
||||
#ifdef HAVE_AFFINITY
|
||||
void bind_to_free_cpu(afl_state_t *);
|
||||
#endif
|
||||
void setup_post(afl_state_t *);
|
||||
void read_testcases(afl_state_t *, u8 *);
|
||||
void perform_dry_run(afl_state_t *);
|
||||
void pivot_inputs(afl_state_t *);
|
||||
@ -1326,7 +1358,6 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) {
|
||||
|
||||
ck_read(afl->fsrv.dev_urandom_fd, &afl->rand_seed, sizeof(afl->rand_seed),
|
||||
"/dev/urandom");
|
||||
// srandom(afl->rand_seed[0]);
|
||||
afl->rand_cnt = (RESEED_RNG / 2) + (afl->rand_seed[1] % RESEED_RNG);
|
||||
|
||||
}
|
||||
@ -1425,7 +1456,7 @@ char *sha1_hex_for_file(const char *fname, u32 len);
|
||||
* enabled. */
|
||||
static inline int permissive_create(afl_state_t *afl, const char *fn) {
|
||||
|
||||
int fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
|
||||
int fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, afl->perm);
|
||||
if (unlikely(fd < 0)) {
|
||||
|
||||
if (!(afl->afl_env.afl_sha1_filenames && errno == EEXIST)) {
|
||||
@ -1436,10 +1467,28 @@ static inline int permissive_create(afl_state_t *afl, const char *fn) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->chown_needed) {
|
||||
|
||||
if (fchown(fd, -1, afl->fsrv.gid) == -1) { PFATAL("fchown() failed"); }
|
||||
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
}
|
||||
|
||||
static inline void bitmap_set(u8 *map, u32 index) {
|
||||
|
||||
map[index / 8] |= (1u << (index % 8));
|
||||
|
||||
}
|
||||
|
||||
static inline u8 bitmap_read(u8 *map, u32 index) {
|
||||
|
||||
return (map[index / 8] >> (index % 8)) & 1;
|
||||
|
||||
}
|
||||
|
||||
#if TESTCASE_CACHE == 1
|
||||
#error define of TESTCASE_CACHE must be zero or larger than 1
|
||||
#endif
|
||||
|
@ -31,7 +31,8 @@ int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
|
||||
if (__cmd == IPC_RMID) {
|
||||
|
||||
int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
|
||||
struct ashmem_pin pin = {0, length};
|
||||
unsigned int safe_length = length >= 0 ? length : 0;
|
||||
struct ashmem_pin pin = {0, safe_length};
|
||||
ret = ioctl(__shmid, ASHMEM_UNPIN, &pin);
|
||||
close(__shmid);
|
||||
|
||||
|
55
include/asanfuzz.h
Normal file
55
include/asanfuzz.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
american fuzzy lop++ - cmplog header
|
||||
------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Dominik Maier <mail@dmnk.co>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Heiko Eissfeldt <heiko.eissfeldt@hexco.de>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2023 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Shared code to handle the shared memory. This is used by the fuzzer
|
||||
as well the other components like afl-tmin, afl-showmap, etc...
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _AFL_ASAMFUZZ_H
|
||||
#define _AFL_ASAMFUZZ_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// new_bits for describe_op
|
||||
// new_bits value 1, 2 and 0x80 are already used!
|
||||
#define SAN_CRASH_ONLY (1 << 4)
|
||||
#define NON_COV_INCREASE_BUG (1 << 5)
|
||||
|
||||
enum SanitizerAbstraction {
|
||||
|
||||
SIMPLIFY_TRACE = 0, // Feed all simplified trace to sanitizers, moderate
|
||||
// sensitive and default for SAND. Not missing bugs.
|
||||
UNIQUE_TRACE, // Feed all unique trace to sanitizers, the most sensitive
|
||||
// and not missing bugs.
|
||||
COVERAGE_INCREASE // Feed all coverage increasing cases to sanitizers, the
|
||||
// least sensitive at a risk of missing ~20% bugs.
|
||||
|
||||
};
|
||||
|
||||
/* Execs the child */
|
||||
|
||||
struct afl_forkserver;
|
||||
void sanfuzz_exec_child(struct afl_forkserver *fsrv, char **argv);
|
||||
|
||||
#endif
|
||||
|
@ -76,8 +76,9 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname);
|
||||
int parse_afl_kill_signal(u8 *numeric_signal_as_str, int default_signal);
|
||||
|
||||
/* Configure the signals that are used to kill the forkserver
|
||||
and the forked childs. If `afl_kill_signal_env` or `afl_fsrv_kill_signal_env`
|
||||
is NULL, the appropiate values are read from the environment. */
|
||||
and the forked children. If `afl_kill_signal_env` or
|
||||
`afl_fsrv_kill_signal_env` is NULL, the appropriate values are read from the
|
||||
environment. */
|
||||
void configure_afl_kill_signals(afl_forkserver_t *fsrv,
|
||||
char *afl_kill_signal_env,
|
||||
char *afl_fsrv_kill_signal_env,
|
||||
@ -143,10 +144,10 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
|
||||
u32 get_map_size(void);
|
||||
|
||||
/* create a stream file */
|
||||
FILE *create_ffile(u8 *fn);
|
||||
FILE *create_ffile(u8 *fn, mode_t perm);
|
||||
|
||||
/* create a file */
|
||||
s32 create_file(u8 *fn);
|
||||
s32 create_file(u8 *fn, mode_t perm);
|
||||
|
||||
/* memmem implementation as not all platforms support this */
|
||||
void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle,
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++4.30c"
|
||||
#define VERSION "++4.33a"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -39,7 +39,7 @@
|
||||
However if a target has problematic constructors and init arrays then
|
||||
this can fail. Hence afl-fuzz deploys a larger default map. The largest
|
||||
map seen so far is the xlsx fuzzer for libreoffice which is 5MB.
|
||||
At runtime this value can be overriden via AFL_MAP_SIZE.
|
||||
At runtime this value can be overridden via AFL_MAP_SIZE.
|
||||
Default: 8MB (defined in bytes) */
|
||||
#define DEFAULT_SHMEM_SIZE (8 * 1024 * 1024)
|
||||
|
||||
@ -49,9 +49,24 @@
|
||||
Default: 300 (seconds) */
|
||||
#define STRATEGY_SWITCH_TIME 1000
|
||||
|
||||
/* Default file permission umode when creating directories */
|
||||
#define DEFAULT_DIRS_PERMISSION 0700
|
||||
|
||||
/* Default file permission umode when creating files (default: 0600) */
|
||||
#define DEFAULT_PERMISSION 0600
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_IOS
|
||||
#undef DEFAULT_PERMISSION
|
||||
#define DEFAULT_PERMISSION 0666
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
#undef DEFAULT_PERMISSION
|
||||
#define DEFAULT_PERMISSION 0666
|
||||
#endif
|
||||
|
||||
/* SkipDet's global configuration */
|
||||
|
||||
#define MINIMAL_BLOCK_SIZE 64
|
||||
@ -85,11 +100,17 @@
|
||||
/* Maximum allowed fails per CMP value. Default: 96 */
|
||||
#define CMPLOG_FAIL_MAX 96
|
||||
|
||||
/*
|
||||
* Effective fuzzing with selective feeding inputs
|
||||
*/
|
||||
|
||||
#define MAX_EXTRA_SAN_BINARY 4
|
||||
|
||||
/* -------------------------------------*/
|
||||
/* Now non-cmplog configuration options */
|
||||
/* -------------------------------------*/
|
||||
|
||||
/* If a persistent target keeps state and found crashes are not reproducable
|
||||
/* If a persistent target keeps state and found crashes are not reproducible
|
||||
then enable this option and set the AFL_PERSISTENT_RECORD env variable
|
||||
to a number. These number of testcases prior and including the crash case
|
||||
will be kept and written to the crash/ directory as RECORD:... files.
|
||||
@ -153,7 +174,9 @@
|
||||
#define EXEC_TM_ROUND 20U
|
||||
|
||||
/* 64bit arch MACRO */
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__))
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \
|
||||
(defined(__riscv) && __riscv_xlen == 64) || defined(__powerpc64le__) || \
|
||||
defined(__s390x__) || defined(__loongarch64))
|
||||
#define WORD_SIZE_64 1
|
||||
#endif
|
||||
|
||||
@ -182,8 +205,8 @@
|
||||
|
||||
/* Maximum number of unique hangs or crashes to record: */
|
||||
|
||||
#define KEEP_UNIQUE_HANG 500U
|
||||
#define KEEP_UNIQUE_CRASH 10000U
|
||||
#define KEEP_UNIQUE_HANG 512U
|
||||
#define KEEP_UNIQUE_CRASH 25600U
|
||||
|
||||
/* Baseline number of random tweaks during a single 'havoc' stage: */
|
||||
|
||||
@ -319,6 +342,10 @@
|
||||
|
||||
#define AVG_SMOOTHING 16
|
||||
|
||||
/* Max length of sync id (the id after -M and -S) */
|
||||
|
||||
#define SYNC_ID_MAX_LEN 50
|
||||
|
||||
/* Sync interval (every n havoc cycles): */
|
||||
|
||||
#define SYNC_INTERVAL 8
|
||||
@ -404,9 +431,15 @@
|
||||
|
||||
#define SHM_ENV_VAR "__AFL_SHM_ID"
|
||||
|
||||
/* Environment variable used to pass SHM FUZZ ID to the called program. */
|
||||
/* Environment variable used to pass shared memory fuzz map id
|
||||
and the mapping size to the called program. */
|
||||
|
||||
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
|
||||
#define SHM_FUZZ_MAP_SIZE_ENV_VAR "__AFL_SHM_FUZZ_MAP_SIZE"
|
||||
|
||||
/* Default size of the shared memory fuzz map.
|
||||
We add 4 byte for one u32 length field. */
|
||||
#define SHM_FUZZ_MAP_SIZE_DEFAULT (MAX_FILE + 4)
|
||||
|
||||
/* Other less interesting, internal-only variables. */
|
||||
|
||||
@ -492,6 +525,9 @@
|
||||
|
||||
#define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID"
|
||||
|
||||
/* ASAN SHM ID */
|
||||
#define AFL_ASAN_FUZZ_SHM_ENV_VAR "__AFL_ASAN_SHM_ID"
|
||||
|
||||
/* CPU Affinity lockfile env var */
|
||||
|
||||
#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE"
|
||||
@ -523,7 +559,7 @@
|
||||
|
||||
#define AFL_TXT_MAX_LEN 65535
|
||||
|
||||
/* What is the minimum percentage of ascii characters present to be classifed
|
||||
/* What is the minimum percentage of ascii characters present to be classified
|
||||
as "is_ascii"? */
|
||||
|
||||
#define AFL_TXT_MIN_PERCENT 99
|
||||
|
@ -1,6 +1,12 @@
|
||||
#ifndef _COVERAGE_H
|
||||
|
||||
#define _COVERAGE_H
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
#define _AFL_INTSIZEVAR u32
|
||||
|
||||
u32 skim(const u32 *virgin, const u32 *current, const u32 *current_end);
|
||||
u32 classify_word(u32 word);
|
||||
|
||||
@ -110,3 +116,5 @@ inline u32 skim(const u32 *virgin, const u32 *current, const u32 *current_end) {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
#ifndef _COVERAGE_H
|
||||
|
||||
#define _COVERAGE_H
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
#define _AFL_INTSIZEVAR u64
|
||||
|
||||
#if (defined(__AVX512F__) && defined(__AVX512DQ__)) || defined(__AVX2__)
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
@ -118,7 +124,7 @@ inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) {
|
||||
/* All bytes are zero. */
|
||||
if (likely(mask == 0xff)) continue;
|
||||
|
||||
/* Look for nonzero bytes and check for new bits. */
|
||||
/* Look for nonzero bytes and check for new bits. */
|
||||
#define UNROLL(x) \
|
||||
if (unlikely(!(mask & (1 << x)) && classify_word(current[x]) & virgin[x])) \
|
||||
return 1
|
||||
@ -192,3 +198,5 @@ inline u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end) {
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -331,6 +331,7 @@ static inline const char *colorfilter(const char *x) {
|
||||
"\n[-] PROGRAM ABORT : " cRST x); \
|
||||
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \
|
||||
__FILE__, (u32)__LINE__); \
|
||||
fflush(stdout); \
|
||||
abort(); \
|
||||
\
|
||||
} while (0)
|
||||
|
@ -10,6 +10,7 @@ static char *afl_environment_deprecated[] = {
|
||||
"AFL_DEFER_FORKSRV",
|
||||
"AFL_POST_LIBRARY",
|
||||
"AFL_PERSISTENT",
|
||||
"AFL_SAN_NO_INST",
|
||||
NULL
|
||||
|
||||
};
|
||||
@ -33,18 +34,19 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_DISABLE_TRIM", "AFL_NO_TRIM", "AFL_DISABLE_LLVM_INSTRUMENTATION",
|
||||
"AFL_DONT_OPTIMIZE", "AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
|
||||
"AFL_DUMB_FORKSRV", "AFL_EARLY_FORKSERVER", "AFL_ENTRYPOINT",
|
||||
"AFL_EXIT_WHEN_DONE", "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES",
|
||||
"AFL_FAST_CAL", "AFL_FINAL_SYNC", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS",
|
||||
"AFL_FRIDA_DRIVER_NO_HOOK", "AFL_FRIDA_EXCLUDE_RANGES",
|
||||
"AFL_FRIDA_INST_CACHE_SIZE", "AFL_FRIDA_INST_COVERAGE_ABSOLUTE",
|
||||
"AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE",
|
||||
"AFL_FRIDA_INST_INSN", "AFL_FRIDA_INST_JIT", "AFL_FRIDA_INST_NO_CACHE",
|
||||
"AFL_FRIDA_INST_NO_DYNAMIC_LOAD", "AFL_FRIDA_INST_NO_OPTIMIZE",
|
||||
"AFL_FRIDA_INST_NO_PREFETCH", "AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
|
||||
"AFL_FRIDA_INST_NO_SUPPRESS", "AFL_FRIDA_INST_RANGES",
|
||||
"AFL_FRIDA_INST_REGS_FILE", "AFL_FRIDA_INST_SEED", "AFL_FRIDA_INST_TRACE",
|
||||
"AFL_FRIDA_INST_TRACE_UNIQUE", "AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE",
|
||||
"AFL_FRIDA_JS_SCRIPT", "AFL_FRIDA_OUTPUT_STDOUT", "AFL_FRIDA_OUTPUT_STDERR",
|
||||
"AFL_EXITPOINT", "AFL_EXIT_WHEN_DONE", "AFL_EXIT_ON_TIME",
|
||||
"AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FINAL_SYNC", "AFL_FORCE_UI",
|
||||
"AFL_FRIDA_DEBUG_MAPS", "AFL_FRIDA_DRIVER_NO_HOOK",
|
||||
"AFL_FRIDA_EXCLUDE_RANGES", "AFL_FRIDA_INST_CACHE_SIZE",
|
||||
"AFL_FRIDA_INST_COVERAGE_ABSOLUTE", "AFL_FRIDA_INST_COVERAGE_FILE",
|
||||
"AFL_FRIDA_INST_DEBUG_FILE", "AFL_FRIDA_INST_INSN", "AFL_FRIDA_INST_JIT",
|
||||
"AFL_FRIDA_INST_NO_CACHE", "AFL_FRIDA_INST_NO_DYNAMIC_LOAD",
|
||||
"AFL_FRIDA_INST_NO_OPTIMIZE", "AFL_FRIDA_INST_NO_PREFETCH",
|
||||
"AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH", "AFL_FRIDA_INST_NO_SUPPRESS",
|
||||
"AFL_FRIDA_INST_RANGES", "AFL_FRIDA_INST_REGS_FILE", "AFL_FRIDA_INST_SEED",
|
||||
"AFL_FRIDA_INST_TRACE", "AFL_FRIDA_INST_TRACE_UNIQUE",
|
||||
"AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE", "AFL_FRIDA_JS_SCRIPT",
|
||||
"AFL_FRIDA_OUTPUT_STDOUT", "AFL_FRIDA_OUTPUT_STDERR",
|
||||
"AFL_FRIDA_PERSISTENT_ADDR", "AFL_FRIDA_PERSISTENT_CNT",
|
||||
"AFL_FRIDA_PERSISTENT_DEBUG", "AFL_FRIDA_PERSISTENT_HOOK",
|
||||
"AFL_FRIDA_PERSISTENT_RET", "AFL_FRIDA_STALKER_ADJACENT_BLOCKS",
|
||||
@ -101,8 +103,8 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_PERSISTENT_RECORD", "AFL_POST_PROCESS_KEEP_ORIGINAL", "AFL_PRELOAD",
|
||||
"AFL_TARGET_ENV", "AFL_PYTHON_MODULE", "AFL_QEMU_CUSTOM_BIN",
|
||||
"AFL_QEMU_COMPCOV", "AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS",
|
||||
"AFL_QEMU_DISABLE_CACHE", "AFL_QEMU_DRIVER_NO_HOOK", "AFL_QEMU_FORCE_DFL",
|
||||
"AFL_QEMU_PERSISTENT_ADDR", "AFL_QEMU_PERSISTENT_CNT",
|
||||
"AFL_QEMU_BLOCK_COV", "AFL_QEMU_DISABLE_CACHE", "AFL_QEMU_DRIVER_NO_HOOK",
|
||||
"AFL_QEMU_FORCE_DFL", "AFL_QEMU_PERSISTENT_ADDR", "AFL_QEMU_PERSISTENT_CNT",
|
||||
"AFL_QEMU_PERSISTENT_GPR", "AFL_QEMU_PERSISTENT_HOOK",
|
||||
"AFL_QEMU_PERSISTENT_MEM", "AFL_QEMU_PERSISTENT_RET",
|
||||
"AFL_QEMU_PERSISTENT_RETADDR_OFFSET", "AFL_QEMU_PERSISTENT_EXITS",
|
||||
@ -117,9 +119,10 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_USE_UBSAN", "AFL_UBSAN_VERBOSE", "AFL_USE_TSAN", "AFL_USE_CFISAN",
|
||||
"AFL_CFISAN_VERBOSE", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT",
|
||||
"AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN",
|
||||
"AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME", NULL
|
||||
|
||||
};
|
||||
"AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME",
|
||||
"AFL_SAN_ABSTRACTION", "AFL_LLVM_ONLY_FSRV", "AFL_GCC_ONLY_FRSV",
|
||||
"AFL_SAN_RECOVER", "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT",
|
||||
"AFL_FORKSRV_UID", "AFL_FORKSRV_GID", NULL};
|
||||
|
||||
extern char *afl_environment_variables[];
|
||||
|
||||
|
@ -137,6 +137,8 @@ typedef struct afl_forkserver {
|
||||
|
||||
u8 last_kill_signal; /* Signal that killed the child */
|
||||
|
||||
u8 last_exit_code; /* Child exit code if counted as a crash */
|
||||
|
||||
bool use_shmem_fuzz; /* use shared mem for test cases */
|
||||
|
||||
bool support_shmem_fuzz; /* set by afl-fuzz */
|
||||
@ -155,10 +157,15 @@ typedef struct afl_forkserver {
|
||||
|
||||
bool no_unlink; /* do not unlink cur_input */
|
||||
|
||||
bool uses_asan; /* Target uses ASAN? */
|
||||
u8 uses_asan; /* Target uses ASAN/LSAN/MSAN? (bit 0/1/2 respectively) */
|
||||
|
||||
bool setenv; /* setenv() to discriminate the forkserver? */
|
||||
|
||||
bool debug; /* debug mode? */
|
||||
|
||||
u8 san_but_not_instrumented; /* Is it sanitizer enabled but not instrumented?
|
||||
*/
|
||||
|
||||
bool uses_crash_exitcode; /* Custom crash exitcode specified? */
|
||||
u8 crash_exitcode; /* The crash exitcode specified */
|
||||
|
||||
@ -167,6 +174,7 @@ typedef struct afl_forkserver {
|
||||
u8 *shmem_fuzz; /* allocated memory for fuzzing */
|
||||
|
||||
char *cmplog_binary; /* the name of the cmplog binary */
|
||||
char *asanfuzz_binary; /* the name of the ASAN binary */
|
||||
|
||||
/* persistent mode replay functionality */
|
||||
u32 persistent_record; /* persistent replay setting */
|
||||
@ -179,6 +187,16 @@ typedef struct afl_forkserver {
|
||||
s32 persistent_record_pid;
|
||||
#endif
|
||||
|
||||
u8 uid_set;
|
||||
uid_t uid;
|
||||
u8 gid_set;
|
||||
pid_t gid;
|
||||
u16 nb_supl_gids;
|
||||
pid_t *supl_gids;
|
||||
|
||||
mode_t perm;
|
||||
u8 chown_needed;
|
||||
|
||||
/* Function to kick off the forkserver child */
|
||||
void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
|
||||
|
||||
@ -234,6 +252,7 @@ typedef enum fsrv_run_result {
|
||||
|
||||
void afl_fsrv_init(afl_forkserver_t *fsrv);
|
||||
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
|
||||
void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0);
|
||||
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
volatile u8 *stop_soon_p, u8 debug_child_output);
|
||||
u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
|
||||
|
@ -2,18 +2,6 @@
|
||||
american fuzzy lop++ - hashing function
|
||||
---------------------------------------
|
||||
|
||||
The hash32() function is a variant of MurmurHash3, a good
|
||||
non-cryptosafe hashing function developed by Austin Appleby.
|
||||
|
||||
For simplicity, this variant does *NOT* accept buffer lengths
|
||||
that are not divisible by 8 bytes. The 32-bit version is otherwise
|
||||
similar to the original; the 64-bit one is a custom hack with
|
||||
mostly-unproven properties.
|
||||
|
||||
Austin's original code is public domain.
|
||||
|
||||
Other code written by Michal Zalewski
|
||||
|
||||
Copyright 2016 Google Inc. All rights reserved.
|
||||
Copyright 2019-2024 AFLplusplus Project. All rights reserved.
|
||||
|
||||
@ -33,82 +21,5 @@
|
||||
u32 hash32(u8 *key, u32 len, u32 seed);
|
||||
u64 hash64(u8 *key, u32 len, u64 seed);
|
||||
|
||||
#if 0
|
||||
|
||||
The following code is disabled because xxh3 is 30% faster
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
|
||||
|
||||
static inline u32 hash32(u8 *key, u32 len, u32 seed) {
|
||||
|
||||
const u64 *data = (u64 *)key;
|
||||
u64 h1 = seed ^ len;
|
||||
|
||||
len >>= 3;
|
||||
|
||||
while (len--) {
|
||||
|
||||
u64 k1 = *data++;
|
||||
|
||||
k1 *= 0x87c37b91114253d5ULL;
|
||||
k1 = ROL64(k1, 31);
|
||||
k1 *= 0x4cf5ad432745937fULL;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROL64(h1, 27);
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
}
|
||||
|
||||
h1 ^= h1 >> 33;
|
||||
h1 *= 0xff51afd7ed558ccdULL;
|
||||
h1 ^= h1 >> 33;
|
||||
h1 *= 0xc4ceb9fe1a85ec53ULL;
|
||||
h1 ^= h1 >> 33;
|
||||
|
||||
return h1;
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
|
||||
|
||||
static inline u32 hash32(const void *key, u32 len, u32 seed) {
|
||||
|
||||
const u32 *data = (u32 *)key;
|
||||
u32 h1 = seed ^ len;
|
||||
|
||||
len >>= 2;
|
||||
|
||||
while (len--) {
|
||||
|
||||
u32 k1 = *data++;
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = ROL32(k1, 15);
|
||||
k1 *= 0x1b873593;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROL32(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
|
||||
}
|
||||
|
||||
h1 ^= h1 >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ^= h1 >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ^= h1 >> 16;
|
||||
|
||||
return h1;
|
||||
|
||||
}
|
||||
|
||||
#endif /* ^__x86_64__ */
|
||||
#endif
|
||||
|
||||
#endif /* !_HAVE_HASH_H */
|
||||
|
||||
|
@ -51,12 +51,14 @@ typedef struct sharedmem {
|
||||
size_t map_size; /* actual allocated size */
|
||||
|
||||
int cmplog_mode;
|
||||
int sanfuzz_mode;
|
||||
int shmemfuzz_mode;
|
||||
struct cmp_map *cmp_map;
|
||||
|
||||
} sharedmem_t;
|
||||
|
||||
u8 *afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode);
|
||||
u8 *afl_shm_init(sharedmem_t *, size_t, unsigned char non_instrumented_mode,
|
||||
mode_t mode, int gid);
|
||||
void afl_shm_deinit(sharedmem_t *);
|
||||
|
||||
#endif
|
||||
|
@ -63,7 +63,7 @@
|
||||
* // To enable unaligned access, but indicate that it significantly slow.
|
||||
* #define T1HA_SYS_UNALIGNED_ACCESS 1
|
||||
*
|
||||
* // To enable unaligned access, and indicate that it effecient.
|
||||
* // To enable unaligned access, and indicate that it's efficient.
|
||||
* #define T1HA_SYS_UNALIGNED_ACCESS 2
|
||||
*
|
||||
*
|
||||
@ -512,7 +512,7 @@ T1HA_API uint64_t t1ha2_atonce128(uint64_t *__restrict extra_result,
|
||||
uint64_t seed);
|
||||
|
||||
/* The init/update/final trinity for streaming.
|
||||
* Return 64 or 128-bit result depentently from `extra_result` argument. */
|
||||
* Return 64 or 128-bit result dependently from `extra_result` argument. */
|
||||
T1HA_API void t1ha2_init(t1ha_context_t *ctx, uint64_t seed_x, uint64_t seed_y);
|
||||
T1HA_API void t1ha2_update(t1ha_context_t *__restrict ctx,
|
||||
const void *__restrict data, size_t length);
|
||||
|
@ -3169,7 +3169,7 @@ static xxh_u32 XXH32_avalanche(xxh_u32 hash) {
|
||||
*/
|
||||
static XXH_PUREF xxh_u32 XXH32_finalize(xxh_u32 hash, const xxh_u8 *ptr,
|
||||
size_t len, XXH_alignment align) {
|
||||
\
|
||||
|
||||
#define XXH_PROCESS1 \
|
||||
do { \
|
||||
\
|
||||
|
@ -29,7 +29,7 @@ Alternatively you can set `AFL_LLVM_INJECTIONS_ALL` to enable all.
|
||||
|
||||
## How to modify
|
||||
|
||||
If you want to add more fuctions to check for e.g. SQL injections:
|
||||
If you want to add more functions to check for e.g. SQL injections:
|
||||
Add these to `instrumentation/injection-pass.cc` and recompile.
|
||||
|
||||
If you want to test for more injection inputs:
|
||||
|
@ -79,11 +79,11 @@ LLVM 13 to 19 should be available in all current Linux repositories.
|
||||
|
||||
That part is easy.
|
||||
Just set `LLVM_CONFIG` to the llvm-config-VERSION and build AFL++, e.g. for
|
||||
LLVM 15:
|
||||
LLVM 19:
|
||||
|
||||
```
|
||||
cd ~/AFLplusplus
|
||||
export LLVM_CONFIG=llvm-config-15
|
||||
export LLVM_CONFIG=llvm-config-19
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
@ -96,7 +96,7 @@ Also, the instrument file listing (AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST ->
|
||||
[README.instrument_list.md](README.instrument_list.md)) and laf-intel/compcov
|
||||
(AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work.
|
||||
|
||||
Example (note that you might need to add the version, e.g. `llvm-ar-15`:
|
||||
Example (note that you might need to add the version, e.g. `llvm-ar-19`:
|
||||
|
||||
```
|
||||
CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as ./configure
|
||||
|
@ -8,7 +8,7 @@ most effective way to fuzz, as the speed can easily be x10 or x20 times faster
|
||||
without any disadvantages. *All professional fuzzing uses this mode.*
|
||||
|
||||
Persistent mode requires that the target can be called in one or more functions,
|
||||
and that it's state can be completely reset so that multiple calls can be
|
||||
and that its state can be completely reset so that multiple calls can be
|
||||
performed without resource leaks, and that earlier runs will have no impact on
|
||||
future runs. An indicator for this is the `stability` value in the `afl-fuzz`
|
||||
UI. If this decreases to lower values in persistent mode compared to
|
||||
|
@ -327,7 +327,16 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
|
||||
|
||||
};
|
||||
|
||||
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
|
||||
|
||||
} else {
|
||||
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -380,8 +389,16 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
|
||||
|
||||
};
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
|
||||
} else {
|
||||
|
||||
if (debug) { DEBUGF("Instrumentation disabled\n"); }
|
||||
|
||||
}
|
||||
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
@ -500,7 +517,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule(
|
||||
}
|
||||
|
||||
// we make this the default as the fixed map has problems with
|
||||
// defered forkserver, early constructors, ifuncs and maybe more
|
||||
// deferred forkserver, early constructors, ifuncs and maybe more
|
||||
/*if (getenv("AFL_LLVM_MAP_DYNAMIC"))*/
|
||||
map_addr = 0;
|
||||
|
||||
@ -1988,8 +2005,11 @@ void ModuleSanitizerCoverageLTO::instrumentFunction(
|
||||
|
||||
}
|
||||
|
||||
extra_ctx_inst += inst_in_this_func * (call_counter - 1);
|
||||
afl_global_id += extra_ctx_inst;
|
||||
uint32_t extra_ctx_inst_in_this_func =
|
||||
inst_in_this_func * (call_counter - 1);
|
||||
|
||||
extra_ctx_inst += extra_ctx_inst_in_this_func;
|
||||
afl_global_id += extra_ctx_inst_in_this_func;
|
||||
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
// #include "llvm/IR/Verifier.h"
|
||||
#if LLVM_VERSION_MAJOR >= 15
|
||||
#if LLVM_VERSION_MAJOR < 17
|
||||
#include "llvm/ADT/Triple.h"
|
||||
@ -76,9 +77,9 @@
|
||||
#else
|
||||
#include "llvm/Transforms/Utils/Instrumentation.h"
|
||||
#endif
|
||||
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
@ -206,7 +207,8 @@ class ModuleSanitizerCoverageAFL
|
||||
|
||||
SanitizerCoverageOptions Options;
|
||||
|
||||
uint32_t instr = 0, selects = 0, unhandled = 0, dump_cc = 0;
|
||||
uint32_t instr = 0, selects = 0, hidden = 0, unhandled = 0, skippedbb = 0,
|
||||
dump_cc = 0;
|
||||
GlobalVariable *AFLMapPtr = NULL;
|
||||
ConstantInt *One = NULL;
|
||||
ConstantInt *Zero = NULL;
|
||||
@ -222,20 +224,29 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR == 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
PB.registerOptimizerEarlyEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(ModuleSanitizerCoverageAFL());
|
||||
|
||||
});
|
||||
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||
|
||||
MPM.addPass(ModuleSanitizerCoverageAFL());
|
||||
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
}};
|
||||
|
||||
}
|
||||
@ -257,8 +268,20 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
|
||||
|
||||
};
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
// TODO: Support LTO or llvm classic?
|
||||
// Note we still need afl-compiler-rt so we just disable the instrumentation
|
||||
// here.
|
||||
if (!getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
|
||||
} else {
|
||||
|
||||
if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); }
|
||||
|
||||
}
|
||||
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
}
|
||||
@ -326,7 +349,7 @@ Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
|
||||
|
||||
if (TargetTriple.isOSBinFormatCOFF()) {
|
||||
|
||||
// In COFF files, if the contructors are set as COMDAT (they are because
|
||||
// In COFF files, if the constructors are set as COMDAT (they are because
|
||||
// COFF supports COMDAT) and the linker flag /OPT:REF (strip unreferenced
|
||||
// functions and data) is used, the constructors get stripped. To prevent
|
||||
// this, give the constructors weak ODR linkage and ensure the linker knows
|
||||
@ -481,9 +504,16 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
|
||||
getenv("AFL_USE_TSAN") ? ", TSAN" : "",
|
||||
getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
|
||||
getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
|
||||
char buf[32] = "";
|
||||
if (skippedbb) {
|
||||
|
||||
snprintf(buf, sizeof(buf), " %u instrumentations saved.", skippedbb);
|
||||
|
||||
}
|
||||
|
||||
OKF("Instrumented %u locations with no collisions (%s mode) of which are "
|
||||
"%u handled and %u unhandled selects.",
|
||||
instr, modeline, selects, unhandled);
|
||||
"%u handled and %u unhandled special instructions.%s",
|
||||
instr, modeline, selects + hidden, unhandled, buf);
|
||||
|
||||
}
|
||||
|
||||
@ -757,11 +787,14 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
if (AllBlocks.empty()) return false;
|
||||
|
||||
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
|
||||
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0, cnt_hidden_sel = 0,
|
||||
cnt_hidden_sel_inc = 0, skip_blocks = 0;
|
||||
static uint32_t first = 1;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
bool block_is_instrumented = false;
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
CallInst *callInst = nullptr;
|
||||
@ -775,11 +808,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (!FuncName.compare(StringRef("dlopen")) ||
|
||||
!FuncName.compare(StringRef("_dlopen"))) {
|
||||
|
||||
fprintf(stderr,
|
||||
"WARNING: dlopen() detected. To have coverage for a library "
|
||||
"that your target dlopen()'s this must either happen before "
|
||||
"__AFL_INIT() or you must use AFL_PRELOAD to preload all "
|
||||
"dlopen()'ed libraries!\n");
|
||||
WARNF(
|
||||
"dlopen() detected. To have coverage for a library that your "
|
||||
"target dlopen()'s this must either happen before __AFL_INIT() "
|
||||
"or you must use AFL_PRELOAD to preload all dlopen()'ed "
|
||||
"libraries!\n");
|
||||
continue;
|
||||
|
||||
}
|
||||
@ -787,53 +820,183 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) {
|
||||
|
||||
cnt_cov++;
|
||||
block_is_instrumented = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SelectInst *selectInst = nullptr;
|
||||
bool instrumentInst = false;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
|
||||
if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
|
||||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
|
||||
|
||||
Value *c = selectInst->getCondition();
|
||||
auto t = c->getType();
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
// || isa<PHINode>(&IN)
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
bool usedInBranch = false, usedInSelectDecision = false;
|
||||
|
||||
}
|
||||
for (auto *U : IN.users()) {
|
||||
|
||||
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
if (isa<BranchInst>(U)) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
usedInBranch = true;
|
||||
break;
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
|
||||
}
|
||||
|
||||
if (auto *sel = dyn_cast<SelectInst>(U)) {
|
||||
|
||||
if (icmp && sel->getCondition() == icmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
|
||||
} else if (fcmp && sel->getCondition() == fcmp) {
|
||||
|
||||
usedInSelectDecision = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!usedInBranch && !usedInSelectDecision) {
|
||||
|
||||
// errs() << "Instrument! " << *(&IN) << "\n";
|
||||
instrumentInst = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (instrumentInst) {
|
||||
|
||||
block_is_instrumented = true;
|
||||
SelectInst *selectInst;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
// PHINode *phiInst;
|
||||
// errs() << "IN: " << *(&IN) << "\n";
|
||||
|
||||
/* if ((phiInst = dyn_cast<PHINode>(&IN))) {
|
||||
|
||||
cnt_hidden_sel++;
|
||||
cnt_hidden_sel_inc += phiInst->getNumIncomingValues();
|
||||
|
||||
} else*/
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
|
||||
|
||||
if (icmp->getType()->isIntegerTy(1)) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
} else {
|
||||
|
||||
unhandled++;
|
||||
|
||||
}
|
||||
|
||||
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
|
||||
|
||||
if (fcmp->getType()->isIntegerTy(1)) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
} else {
|
||||
|
||||
unhandled++;
|
||||
|
||||
}
|
||||
|
||||
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
|
||||
Value *c = selectInst->getCondition();
|
||||
auto t = c->getType();
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += 2;
|
||||
|
||||
} else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
|
||||
cnt_sel++;
|
||||
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
WARNF("unknown select ID type: %u\n", t->getTypeID());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} /*else {
|
||||
|
||||
cnt_hidden_sel++;
|
||||
cnt_hidden_sel_inc += 2;
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (block_is_instrumented && &BB != &BB.getParent()->getEntryBlock() &&
|
||||
llvm::is_contained(AllBlocks, &BB)) {
|
||||
|
||||
Instruction *instr = &*BB.begin();
|
||||
LLVMContext &Ctx = BB.getContext();
|
||||
MDNode *md = MDNode::get(Ctx, MDString::get(Ctx, "skipinstrument"));
|
||||
instr->setMetadata("tag", md);
|
||||
skip_blocks++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc);
|
||||
uint32_t xtra = 0;
|
||||
if (skip_blocks < first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc) {
|
||||
|
||||
xtra = first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc - skip_blocks;
|
||||
|
||||
}
|
||||
|
||||
CreateFunctionLocalArrays(F, AllBlocks, xtra);
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
WARNF(
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit instrumentation.");
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if (first) { first = 0; }
|
||||
selects += cnt_sel;
|
||||
hidden += cnt_hidden_sel;
|
||||
|
||||
uint32_t special = 0, local_selects = 0, skip_next = 0;
|
||||
uint32_t special = 0, local_selects = 0, skip_select = 0, skip_icmp = 0;
|
||||
// uint32_t skip_phi = 0;
|
||||
|
||||
for (auto &BB : F) {
|
||||
|
||||
// errs() << *(&BB) << "\n";
|
||||
|
||||
for (auto &IN : BB) {
|
||||
|
||||
// errs() << *(&IN) << "\n";
|
||||
CallInst *callInst = nullptr;
|
||||
|
||||
if ((callInst = dyn_cast<CallInst>(&IN))) {
|
||||
@ -851,15 +1014,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
IRBuilder<> IRB(callInst);
|
||||
#endif
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
Value *GuardPtr = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
@ -873,132 +1027,322 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
}
|
||||
|
||||
SelectInst *selectInst = nullptr;
|
||||
bool instrumentInst = false;
|
||||
ICmpInst *icmp;
|
||||
FCmpInst *fcmp;
|
||||
|
||||
if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
|
||||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
|
||||
|
||||
uint32_t vector_cnt = 0;
|
||||
Value *condition = selectInst->getCondition();
|
||||
Value *result;
|
||||
auto t = condition->getType();
|
||||
IRBuilder<> IRB(selectInst->getNextNode());
|
||||
// || isa<PHINode>(&IN)
|
||||
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
bool usedInBranch = false, usedInSelectDecision = false;
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
for (auto *U : IN.users()) {
|
||||
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
if (isa<BranchInst>(U)) {
|
||||
|
||||
usedInBranch = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
auto GuardPtr1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
if (auto *sel = dyn_cast<SelectInst>(U)) {
|
||||
|
||||
auto GuardPtr2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
if (icmp && sel->getCondition() == icmp) {
|
||||
|
||||
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
|
||||
usedInSelectDecision = true;
|
||||
break;
|
||||
|
||||
} else
|
||||
} else if (fcmp && sel->getCondition() == fcmp) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
if (tt) {
|
||||
|
||||
uint32_t elements = tt->getElementCount().getFixedValue();
|
||||
vector_cnt = elements;
|
||||
if (elements) {
|
||||
|
||||
FixedVectorType *GuardPtr1 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
FixedVectorType *GuardPtr2 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
Value *x, *y;
|
||||
|
||||
if (!FunctionGuardArray) {
|
||||
|
||||
fprintf(stderr,
|
||||
"SANCOV: FunctionGuardArray is NULL, failed to emit "
|
||||
"instrumentation.");
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
Value *val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
|
||||
|
||||
Value *val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
|
||||
|
||||
for (uint64_t i = 1; i < elements; i++) {
|
||||
|
||||
val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(x, val1, i);
|
||||
|
||||
val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(y, val2, i);
|
||||
|
||||
}
|
||||
|
||||
result = IRB.CreateSelect(condition, x, y);
|
||||
usedInSelectDecision = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
}
|
||||
|
||||
#endif
|
||||
{
|
||||
if (!usedInBranch && !usedInSelectDecision) {
|
||||
|
||||
// fprintf(stderr, "UNHANDLED: %u\n", t->getTypeID());
|
||||
unhandled++;
|
||||
continue;
|
||||
// errs() << "Instrument! " << *(&IN) << "\n";
|
||||
instrumentInst = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (instrumentInst) {
|
||||
|
||||
Value *result = nullptr;
|
||||
uint32_t vector_cnt = 0;
|
||||
SelectInst *selectInst;
|
||||
// PHINode *phi = nullptr, *newPhi = nullptr;
|
||||
IRBuilder<> IRB(IN.getNextNode());
|
||||
|
||||
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
|
||||
|
||||
if (!icmp->getType()->isIntegerTy(1)) { continue; }
|
||||
|
||||
if (skip_icmp) {
|
||||
|
||||
skip_icmp--;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
|
||||
if (DILocation *Loc = IN.getDebugLoc()) {
|
||||
|
||||
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
|
||||
<< Loc->getLine() << ":";
|
||||
std::string path =
|
||||
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
|
||||
std::ifstream sourceFile(path);
|
||||
std::string lineContent;
|
||||
for (unsigned line = 1; line <= Loc->getLine(); ++line)
|
||||
std::getline(sourceFile, lineContent);
|
||||
llvm::errs() << lineContent << "\n";
|
||||
|
||||
}
|
||||
|
||||
errs() << *(&IN) << "\n";
|
||||
|
||||
}
|
||||
|
||||
auto res = icmp;
|
||||
auto GuardPtr1 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
auto GuardPtr2 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
|
||||
skip_select = 1;
|
||||
// fprintf(stderr, "Icmp!\n");
|
||||
|
||||
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
|
||||
|
||||
if (!fcmp->getType()->isIntegerTy(1)) { continue; }
|
||||
|
||||
if (debug) {
|
||||
|
||||
if (DILocation *Loc = IN.getDebugLoc()) {
|
||||
|
||||
llvm::errs() << "DEBUG " << Loc->getFilename() << ":"
|
||||
<< Loc->getLine() << ":";
|
||||
std::string path =
|
||||
Loc->getDirectory().str() + "/" + Loc->getFilename().str();
|
||||
std::ifstream sourceFile(path);
|
||||
std::string lineContent;
|
||||
for (unsigned line = 1; line <= Loc->getLine(); ++line)
|
||||
std::getline(sourceFile, lineContent);
|
||||
llvm::errs() << lineContent << "\n";
|
||||
|
||||
}
|
||||
|
||||
errs() << *(&IN) << "\n";
|
||||
|
||||
}
|
||||
|
||||
auto res = fcmp;
|
||||
auto GuardPtr1 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
auto GuardPtr2 = IRB.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
{IRB.getInt64(0),
|
||||
IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))});
|
||||
|
||||
result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2);
|
||||
skip_select = 1;
|
||||
// fprintf(stderr, "Fcmp!\n");
|
||||
|
||||
/*} else if ((phi = dyn_cast<PHINode>(&IN))) {
|
||||
|
||||
if (skip_phi) {
|
||||
|
||||
skip_phi = 0;
|
||||
// errs() << "SKIP: " << *(&IN) << "\n";
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// errs() << "-->PHI: " << *(&IN) << "\n";
|
||||
// continue;
|
||||
Instruction *insertBefore =
|
||||
&*phi->getParent()->getFirstInsertionPt(); newPhi =
|
||||
PHINode::Create(Int32PtrTy, 0, "", insertBefore); BasicBlock
|
||||
*phiBlock = phi->getParent();
|
||||
|
||||
for (BasicBlock *pred : predecessors(phiBlock)) {
|
||||
|
||||
IRBuilder<> predBuilder(pred->getTerminator());
|
||||
|
||||
Value *ptr = predBuilder.CreateInBoundsGEP(
|
||||
FunctionGuardArray->getValueType(), FunctionGuardArray,
|
||||
ConstantInt::get(
|
||||
IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()))); newPhi->addIncoming(ptr, pred);
|
||||
|
||||
}
|
||||
|
||||
result = newPhi;
|
||||
skip_phi = 1;
|
||||
// fprintf(stderr, "Phi!\n");
|
||||
*/
|
||||
|
||||
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
|
||||
|
||||
if (skip_select) {
|
||||
|
||||
skip_select = 0;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
// fprintf(stderr, "Select!\n");
|
||||
|
||||
}
|
||||
|
||||
Value *condition = selectInst->getCondition();
|
||||
auto t = condition->getType();
|
||||
|
||||
if (t->getTypeID() == llvm::Type::IntegerTyID) {
|
||||
|
||||
auto GuardPtr1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
auto GuardPtr2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
|
||||
Int32PtrTy);
|
||||
|
||||
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
|
||||
skip_select = 1;
|
||||
|
||||
} else
|
||||
|
||||
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
|
||||
|
||||
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
|
||||
|
||||
if (tt) {
|
||||
|
||||
uint32_t elements = tt->getElementCount().getFixedValue();
|
||||
vector_cnt = elements;
|
||||
if (elements) {
|
||||
|
||||
FixedVectorType *GuardPtr1 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
FixedVectorType *GuardPtr2 =
|
||||
FixedVectorType::get(Int32PtrTy, elements);
|
||||
Value *x, *y;
|
||||
|
||||
Value *val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
|
||||
|
||||
Value *val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ +
|
||||
AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
|
||||
|
||||
for (uint64_t i = 1; i < elements; i++) {
|
||||
|
||||
val1 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
x = IRB.CreateInsertElement(x, val1, i);
|
||||
|
||||
val2 = IRB.CreateIntToPtr(
|
||||
IRB.CreateAdd(
|
||||
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
|
||||
ConstantInt::get(
|
||||
IntptrTy,
|
||||
(cnt_cov + local_selects++ + AllBlocks.size()) *
|
||||
4)),
|
||||
Int32PtrTy);
|
||||
y = IRB.CreateInsertElement(y, val2, i);
|
||||
|
||||
}
|
||||
|
||||
result = IRB.CreateSelect(condition, x, y);
|
||||
skip_select = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
{
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
WARNF("Warning: Unhandled ID type: %u\n", t->getTypeID());
|
||||
|
||||
}
|
||||
|
||||
unhandled++;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint32_t vector_cur = 0;
|
||||
|
||||
/* Load SHM pointer */
|
||||
/*
|
||||
if (newPhi) {
|
||||
|
||||
auto *inst = dyn_cast<Instruction>(result);
|
||||
PHINode *nphi;
|
||||
|
||||
while ((nphi = dyn_cast<PHINode>(inst))) {
|
||||
|
||||
// fprintf(stderr, "NEXT!\n");
|
||||
inst = inst->getNextNode();
|
||||
|
||||
}
|
||||
|
||||
IRB.SetInsertPoint(inst);
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
LoadInst *MapPtr =
|
||||
IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
|
||||
@ -1030,9 +1374,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
if (use_threadsafe_counters) {
|
||||
|
||||
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
llvm::MaybeAlign(1),
|
||||
#endif
|
||||
llvm::AtomicOrdering::Monotonic);
|
||||
|
||||
} else {
|
||||
@ -1049,6 +1391,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
auto cf = IRB.CreateICmpEQ(Incr, Zero);
|
||||
auto carry = IRB.CreateZExt(cf, Int8Ty);
|
||||
Incr = IRB.CreateAdd(Incr, carry);
|
||||
skip_icmp++;
|
||||
|
||||
}
|
||||
|
||||
@ -1070,13 +1413,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
}
|
||||
|
||||
skip_next = 1;
|
||||
instr += vector_cnt;
|
||||
|
||||
} else {
|
||||
|
||||
skip_next = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1085,9 +1423,40 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
|
||||
|
||||
if (AllBlocks.empty() && !special && !local_selects) return false;
|
||||
|
||||
if (!AllBlocks.empty())
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++)
|
||||
InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
|
||||
uint32_t skipped = 0;
|
||||
|
||||
if (!AllBlocks.empty()) {
|
||||
|
||||
for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
|
||||
|
||||
auto instr = AllBlocks[i]->begin();
|
||||
if (instr->getMetadata("skipinstrument")) {
|
||||
|
||||
skipped++;
|
||||
// fprintf(stderr, "Skipped!\n");
|
||||
|
||||
} else {
|
||||
|
||||
InjectCoverageAtBlock(F, *AllBlocks[i], i - skipped, IsLeafFunc);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
skippedbb += skipped;
|
||||
|
||||
/*
|
||||
if (verifyFunction(F, &errs())) {
|
||||
|
||||
errs() << "Broken function after instrumentation\n";
|
||||
F.print(errs(), nullptr);
|
||||
report_fatal_error("Invalid IR");
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return true;
|
||||
|
||||
@ -1257,10 +1626,7 @@ void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function &F,
|
||||
if (use_threadsafe_counters) {
|
||||
|
||||
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
llvm::MaybeAlign(1),
|
||||
#endif
|
||||
llvm::AtomicOrdering::Monotonic);
|
||||
llvm::MaybeAlign(1), llvm::AtomicOrdering::Monotonic);
|
||||
|
||||
} else {
|
||||
|
||||
@ -1328,4 +1694,3 @@ std::string ModuleSanitizerCoverageAFL::getSectionEnd(
|
||||
return "__stop___" + Section;
|
||||
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __AFL_CODE_COVERAGE
|
||||
@ -120,6 +119,8 @@ u64 __afl_map_addr;
|
||||
u32 __afl_first_final_loc;
|
||||
u32 __afl_old_forkserver;
|
||||
|
||||
u8 __afl_forkserver_setenv = 0;
|
||||
|
||||
#ifdef __AFL_CODE_COVERAGE
|
||||
typedef struct afl_module_info_t afl_module_info_t;
|
||||
|
||||
@ -293,6 +294,25 @@ static void __afl_map_shm_fuzz() {
|
||||
u8 *map = NULL;
|
||||
|
||||
#ifdef USEMMAP
|
||||
|
||||
// Newer afl-fuzz versions will set a shm_fuzz page size env, else fall back
|
||||
size_t shm_fuzz_map_size = SHM_FUZZ_MAP_SIZE_DEFAULT;
|
||||
char *map_size_env = getenv(SHM_FUZZ_MAP_SIZE_ENV_VAR);
|
||||
if (map_size_env != NULL) {
|
||||
|
||||
char *endptr;
|
||||
errno = 0;
|
||||
shm_fuzz_map_size = (size_t)strtoul(map_size_env, &endptr, 10);
|
||||
if (errno != 0 || shm_fuzz_map_size == 0) {
|
||||
|
||||
perror("shm_fuzz mapping size parsing");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const char *shm_file_path = id_str;
|
||||
int shm_fd = -1;
|
||||
|
||||
@ -306,8 +326,7 @@ static void __afl_map_shm_fuzz() {
|
||||
|
||||
}
|
||||
|
||||
map =
|
||||
(u8 *)mmap(0, MAX_FILE + sizeof(u32), PROT_READ, MAP_SHARED, shm_fd, 0);
|
||||
map = (u8 *)mmap(0, shm_fuzz_map_size, PROT_READ, MAP_SHARED, shm_fd, 0);
|
||||
|
||||
#else
|
||||
u32 shm_id = atoi(id_str);
|
||||
@ -358,11 +377,12 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if (__afl_final_loc) {
|
||||
|
||||
__afl_map_size = ++__afl_final_loc; // as we count starting 0
|
||||
__afl_map_size = __afl_final_loc + 1; // as we count starting 0
|
||||
|
||||
if (getenv("AFL_DUMP_MAP_SIZE")) {
|
||||
|
||||
printf("%u\n", __afl_map_size);
|
||||
fflush(stdout);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
@ -601,9 +621,9 @@ static void __afl_map_shm(void) {
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr_dummy = (u8 *)malloc(__afl_final_loc);
|
||||
__afl_map_size = __afl_final_loc + 1;
|
||||
__afl_area_ptr_dummy = (u8 *)malloc(__afl_map_size);
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
__afl_map_size = __afl_final_loc;
|
||||
|
||||
if (!__afl_area_ptr_dummy) {
|
||||
|
||||
@ -889,13 +909,19 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT") != NULL) {
|
||||
|
||||
__afl_forkserver_setenv = 1;
|
||||
|
||||
}
|
||||
|
||||
/* Phone home and tell the parent that we're OK. If parent isn't there,
|
||||
assume we're not running in forkserver mode and just execute program. */
|
||||
|
||||
if (!__afl_old_forkserver) {
|
||||
// return because possible non-forkserver usage
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { return; }
|
||||
|
||||
// return because possible non-forkserver usage
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { return; }
|
||||
if (!__afl_old_forkserver) {
|
||||
|
||||
if (read(FORKSRV_FD, reply, 4) != 4) { _exit(1); }
|
||||
if (tmp != status2) {
|
||||
@ -914,7 +940,12 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
}
|
||||
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) {
|
||||
|
||||
errno = 0;
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
// Now send the parameters for the set options, increasing by option number
|
||||
|
||||
@ -1055,6 +1086,13 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
|
||||
if (unlikely(__afl_forkserver_setenv)) {
|
||||
|
||||
unsetenv("AFL_FORKSERVER_PARENT");
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@ -1227,6 +1265,15 @@ void __afl_manual_init(void) {
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV") || getenv("AFL_GCC_ONLY_FRSV")) {
|
||||
|
||||
fprintf(stderr,
|
||||
"DEBUG: Overwrite area_ptr to dummy due to "
|
||||
"AFL_LLVM_ONLY_FSRV/AFL_GCC_ONLY_FRSV\n");
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
|
||||
}
|
||||
|
||||
if (!init_done) {
|
||||
|
||||
__afl_start_forkserver();
|
||||
@ -2670,6 +2717,89 @@ void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
|
||||
|
||||
}
|
||||
|
||||
/* llvm weak hooks */
|
||||
|
||||
void __sanitizer_weak_hook_memcmp(void *pc, const void *s1, const void *s2,
|
||||
size_t n, int result) {
|
||||
|
||||
__cmplog_rtn_hook_n((u8 *)s1, (u8 *)s2, (u64)n);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_memmem(void *pc, const void *s1, size_t len1,
|
||||
const void *s2, size_t len2, void *result) {
|
||||
|
||||
__cmplog_rtn_hook_n((u8 *)s1, (u8 *)s2, len1 < len2 ? (u64)len1 : (u64)len2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strncasecmp(void *pc, const void *s1, const void *s2,
|
||||
size_t n, int result) {
|
||||
|
||||
__cmplog_rtn_hook_strn((u8 *)s1, (u8 *)s2, (u64)n);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strncasestr(void *pc, const void *s1, const void *s2,
|
||||
size_t n, char *result) {
|
||||
|
||||
__cmplog_rtn_hook_strn((u8 *)s1, (u8 *)s2, (u64)n);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strncmp(void *pc, const void *s1, const void *s2,
|
||||
size_t n, int result) {
|
||||
|
||||
__cmplog_rtn_hook_strn((u8 *)s1, (u8 *)s2, (u64)n);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strcasecmp(void *pc, const void *s1, const void *s2,
|
||||
int result) {
|
||||
|
||||
__cmplog_rtn_hook_str((u8 *)s1, (u8 *)s2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strcasestr(void *pc, const void *s1, const void *s2,
|
||||
size_t n, char *result) {
|
||||
|
||||
__cmplog_rtn_hook_str((u8 *)s1, (u8 *)s2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strcmp(void *pc, const void *s1, const void *s2,
|
||||
int result) {
|
||||
|
||||
__cmplog_rtn_hook_str((u8 *)s1, (u8 *)s2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strstr(void *pc, const void *s1, const void *s2,
|
||||
char *result) {
|
||||
|
||||
__cmplog_rtn_hook_str((u8 *)s1, (u8 *)s2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
/* COVERAGE manipulation features */
|
||||
|
||||
// this variable is then used in the shm setup to create an additional map
|
||||
|
@ -44,8 +44,8 @@ static const struct pass_data afl_cmplog_pass_data = {
|
||||
.properties_provided = 0,
|
||||
.properties_destroyed = 0,
|
||||
.todo_flags_start = 0,
|
||||
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il |
|
||||
TODO_rebuild_cgraph_edges),
|
||||
.todo_flags_finish =
|
||||
(TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges),
|
||||
|
||||
};
|
||||
|
||||
|
@ -44,8 +44,8 @@ static const struct pass_data afl_cmptrs_pass_data = {
|
||||
.properties_provided = 0,
|
||||
.properties_destroyed = 0,
|
||||
.todo_flags_start = 0,
|
||||
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il |
|
||||
TODO_rebuild_cgraph_edges),
|
||||
.todo_flags_finish =
|
||||
(TODO_update_ssa | TODO_cleanup_cfg | TODO_rebuild_cgraph_edges),
|
||||
|
||||
};
|
||||
|
||||
|
@ -65,7 +65,6 @@
|
||||
The new pass is to be a GIMPLE_PASS. Given the sort of
|
||||
instrumentation it's supposed to do, its todo_flags_finish will
|
||||
certainly need TODO_update_ssa, and TODO_cleanup_cfg.
|
||||
TODO_verify_il is probably desirable, at least during debugging.
|
||||
TODO_rebuild_cgraph_edges is required only in the out-of-line
|
||||
instrumentation mode.
|
||||
|
||||
@ -148,7 +147,7 @@ static constexpr struct pass_data afl_pass_data = {
|
||||
.properties_provided = 0,
|
||||
.properties_destroyed = 0,
|
||||
.todo_flags_start = 0,
|
||||
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg | TODO_verify_il),
|
||||
.todo_flags_finish = (TODO_update_ssa | TODO_cleanup_cfg),
|
||||
|
||||
};
|
||||
|
||||
@ -462,6 +461,7 @@ static struct plugin_info afl_plugin = {
|
||||
.help = G_("AFL gcc plugin\n\
|
||||
\n\
|
||||
Set AFL_QUIET in the environment to silence it.\n\
|
||||
Set AFL_GCC_ONLY_FRSV in the environment to disable instrumentation.\n\
|
||||
\n\
|
||||
Set AFL_INST_RATIO in the environment to a number from 0 to 100\n\
|
||||
to control how likely a block will be chosen for instrumentation.\n\
|
||||
@ -502,9 +502,10 @@ int plugin_init(struct plugin_name_args *info,
|
||||
case it was specified in the command line's -frandom-seed for
|
||||
reproducible instrumentation. */
|
||||
srandom(get_random_seed(false));
|
||||
bool fsrv_only = !!getenv("AFL_GCC_ONLY_FRSV");
|
||||
|
||||
const char *name = info->base_name;
|
||||
register_callback(name, PLUGIN_INFO, NULL, &afl_plugin);
|
||||
if (!fsrv_only) { register_callback(name, PLUGIN_INFO, NULL, &afl_plugin); }
|
||||
|
||||
afl_pass *aflp = new afl_pass(quiet, inst_ratio);
|
||||
struct register_pass_info pass_info = {
|
||||
@ -516,14 +517,20 @@ int plugin_init(struct plugin_name_args *info,
|
||||
|
||||
};
|
||||
|
||||
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
|
||||
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
|
||||
pass_info.pass);
|
||||
if (!fsrv_only) {
|
||||
|
||||
register_callback(name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
|
||||
register_callback(name, PLUGIN_FINISH, afl_pass::plugin_finalize,
|
||||
pass_info.pass);
|
||||
|
||||
}
|
||||
|
||||
if (!quiet)
|
||||
ACTF(G_("%s instrumentation at ratio of %u%% in %s mode."),
|
||||
aflp->out_of_line ? G_("Call-based") : G_("Inline"), inst_ratio,
|
||||
getenv("AFL_HARDEN") ? G_("hardened") : G_("non-hardened"));
|
||||
else if (fsrv_only)
|
||||
ACTF("Instrumentation disabled due to AFL_GCC_ONLY_FRSV");
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -85,10 +85,7 @@ char *getBBName(const llvm::BasicBlock *BB) {
|
||||
std::string Str;
|
||||
raw_string_ostream OS(Str);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
|
||||
BB->printAsOperand(OS, false);
|
||||
#endif
|
||||
name = strdup(OS.str().c_str());
|
||||
return name;
|
||||
|
||||
@ -157,7 +154,7 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
||||
// mangled name of the user-written function
|
||||
for (auto const &ignoreListFunc : ignoreSubstringList) {
|
||||
|
||||
// hexcoder: F->getName().contains() not avaiilable in llvm 3.8.0
|
||||
// hexcoder: F->getName().contains() not available in llvm 3.8.0
|
||||
if (StringRef::npos != F->getName().find(ignoreListFunc)) { return true; }
|
||||
|
||||
}
|
||||
@ -339,9 +336,6 @@ void scanForDangerousFunctions(llvm::Module *M) {
|
||||
|
||||
if (!M) return;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9)
|
||||
|
||||
for (GlobalIFunc &IF : M->ifuncs()) {
|
||||
|
||||
StringRef ifunc_name = IF.getName();
|
||||
@ -408,8 +402,6 @@ void scanForDangerousFunctions(llvm::Module *M) {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static std::string getSourceName(llvm::Function *F) {
|
||||
@ -420,8 +412,6 @@ static std::string getSourceName(llvm::Function *F) {
|
||||
IRBuilder<> IRB(&(*IP));
|
||||
DebugLoc Loc = IP->getDebugLoc();
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
|
||||
if (Loc) {
|
||||
|
||||
StringRef instFilename;
|
||||
@ -442,20 +432,6 @@ static std::string getSourceName(llvm::Function *F) {
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
if (!Loc.isUnknown()) {
|
||||
|
||||
DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
|
||||
|
||||
StringRef instFilename = cDILoc.getFilename();
|
||||
|
||||
/* Continue only if we know where we actually are */
|
||||
return instFilename.str();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return std::string("");
|
||||
|
||||
}
|
||||
|
@ -18,9 +18,6 @@
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
|
||||
typedef long double max_align_t;
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
@ -32,27 +29,16 @@ typedef long double max_align_t;
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 3 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#else
|
||||
#include "llvm/DebugInfo.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#endif
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11
|
||||
#define MNAME M.getSourceFileName()
|
||||
#define FMNAME F.getParent()->getSourceFileName()
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#define MNAME M.getSourceFileName()
|
||||
#define FMNAME F.getParent()->getSourceFileName()
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
// None becomes deprecated
|
||||
// the standard std::nullopt_t is recommended instead
|
||||
// from C++17 and onwards.
|
||||
constexpr std::nullopt_t None = std::nullopt;
|
||||
#endif
|
||||
#else
|
||||
#define MNAME std::string("")
|
||||
#define FMNAME std::string("")
|
||||
#endif
|
||||
|
||||
char *getBBName(const llvm::BasicBlock *BB);
|
||||
|
@ -39,13 +39,9 @@
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#endif
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
@ -72,7 +68,6 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
class AFLdict2filePass : public PassInfoMixin<AFLdict2filePass> {
|
||||
|
||||
std::ofstream of;
|
||||
@ -81,35 +76,16 @@ class AFLdict2filePass : public PassInfoMixin<AFLdict2filePass> {
|
||||
public:
|
||||
AFLdict2filePass() {
|
||||
|
||||
#else
|
||||
|
||||
class AFLdict2filePass : public ModulePass {
|
||||
|
||||
std::ofstream of;
|
||||
void dict2file(u8 *, u32);
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
AFLdict2filePass() : ModulePass(ID) {
|
||||
|
||||
#endif
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_MAJOR >= 11
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
llvmGetPassPluginInfo() {
|
||||
|
||||
@ -117,24 +93,22 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(AFLdict2filePass());
|
||||
MPM.addPass(AFLdict2filePass());
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
char AFLdict2filePass::ID = 0;
|
||||
#endif
|
||||
|
||||
void AFLdict2filePass::dict2file(u8 *mem, u32 len) {
|
||||
|
||||
u32 i, j, binary = 0;
|
||||
@ -174,14 +148,8 @@ void AFLdict2filePass::dict2file(u8 *mem, u32 len) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses AFLdict2filePass::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
#else
|
||||
bool AFLdict2filePass::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
DenseMap<Value *, std::string *> valueMap;
|
||||
char *ptr;
|
||||
int found = 0, handle_main = 1;
|
||||
@ -208,12 +176,8 @@ bool AFLdict2filePass::runOnModule(Module &M) {
|
||||
|
||||
if (!ptr) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
auto PA = PreservedAnalyses::all();
|
||||
return PA;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -749,32 +713,7 @@ bool AFLdict2filePass::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
auto PA = PreservedAnalyses::all();
|
||||
return PA;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
|
||||
static void registerAFLdict2filePass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLdict2filePass());
|
||||
|
||||
}
|
||||
|
||||
static RegisterPass<AFLdict2filePass> X("afl-dict2file",
|
||||
"AFL++ dict2file instrumentation pass",
|
||||
false, false);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLdict2filePass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerAFLdict2filePass);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLdict2filePass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLdict2filePass);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -43,9 +43,7 @@
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#endif
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
|
||||
#include "afl-llvm-common.h"
|
||||
|
||||
@ -80,15 +78,17 @@ llvmGetPassPluginInfo() {
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
|
||||
OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||
) {
|
||||
|
||||
MPM.addPass(AFLcheckIfInstrument());
|
||||
MPM.addPass(AFLcheckIfInstrument());
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}};
|
||||
|
||||
@ -130,15 +130,8 @@ PreservedAnalyses AFLcheckIfInstrument::run(Module &M,
|
||||
|
||||
auto &Ctx = F.getContext();
|
||||
AttributeList Attrs = F.getAttributes();
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
AttributeList NewAttrs = Attrs.addFnAttribute(Ctx, "skipinstrument");
|
||||
F.setAttributes(NewAttrs);
|
||||
#else
|
||||
AttrBuilder NewAttrs;
|
||||
NewAttrs.addAttribute("skipinstrument");
|
||||
F.setAttributes(
|
||||
Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -149,20 +142,3 @@ PreservedAnalyses AFLcheckIfInstrument::run(Module &M,
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void registerAFLcheckIfInstrumentpass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLcheckIfInstrument());
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass(
|
||||
PassManagerBuilder::EP_ModuleOptimizerEarly,
|
||||
registerAFLcheckIfInstrumentpass);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0,
|
||||
registerAFLcheckIfInstrumentpass);
|
||||
#endif
|
||||
|
||||
|
@ -38,30 +38,17 @@ typedef long double max_align_t;
|
||||
#endif
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#else
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#endif
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#endif
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 4 || \
|
||||
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#else
|
||||
#include "llvm/DebugInfo.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#endif
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
||||
@ -72,30 +59,16 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
class AFLCoverage : public PassInfoMixin<AFLCoverage> {
|
||||
|
||||
public:
|
||||
AFLCoverage() {
|
||||
|
||||
#else
|
||||
class AFLCoverage : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
AFLCoverage() : ModulePass(ID) {
|
||||
|
||||
#endif
|
||||
|
||||
initInstrumentList();
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
#else
|
||||
bool runOnModule(Module &M) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
uint32_t ngram_size = 0;
|
||||
@ -109,93 +82,37 @@ class AFLCoverage : public ModulePass {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
llvmGetPassPluginInfo() {
|
||||
extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() {
|
||||
|
||||
return {LLVM_PLUGIN_API_VERSION, "AFLCoverage", "v0.1",
|
||||
/* lambda to insert our pass into the pass pipeline. */
|
||||
[](PassBuilder &PB) {
|
||||
|
||||
#if 1
|
||||
#if LLVM_VERSION_MAJOR <= 13
|
||||
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||
#endif
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
#if LLVM_VERSION_MAJOR >= 16
|
||||
PB.registerOptimizerEarlyEPCallback(
|
||||
#else
|
||||
#else
|
||||
PB.registerOptimizerLastEPCallback(
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||
#endif
|
||||
[](ModulePassManager &MPM, OptimizationLevel OL
|
||||
#if LLVM_VERSION_MAJOR >= 20
|
||||
,
|
||||
ThinOrFullLTOPhase Phase
|
||||
#endif
|
||||
) {
|
||||
|
||||
MPM.addPass(AFLCoverage());
|
||||
|
||||
});
|
||||
|
||||
/* TODO LTO registration */
|
||||
#else
|
||||
using PipelineElement = typename PassBuilder::PipelineElement;
|
||||
PB.registerPipelineParsingCallback([](StringRef Name,
|
||||
ModulePassManager &MPM,
|
||||
ArrayRef<PipelineElement>) {
|
||||
|
||||
if (Name == "AFLCoverage") {
|
||||
|
||||
MPM.addPass(AFLCoverage());
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char AFLCoverage::ID = 0;
|
||||
#endif
|
||||
|
||||
/* needed up to 3.9.0 */
|
||||
#if LLVM_VERSION_MAJOR == 3 && \
|
||||
(LLVM_VERSION_MINOR < 9 || \
|
||||
(LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1))
|
||||
uint64_t PowerOf2Ceil(unsigned in) {
|
||||
|
||||
uint64_t in64 = in - 1;
|
||||
in64 |= (in64 >> 1);
|
||||
in64 |= (in64 >> 2);
|
||||
in64 |= (in64 >> 4);
|
||||
in64 |= (in64 >> 8);
|
||||
in64 |= (in64 >> 16);
|
||||
in64 |= (in64 >> 32);
|
||||
return in64 + 1;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* #if LLVM_VERSION_STRING >= "4.0.1" */
|
||||
#if LLVM_VERSION_MAJOR >= 5 || \
|
||||
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
|
||||
#define AFL_HAVE_VECTOR_INTRINSICS 1
|
||||
#endif
|
||||
#define AFL_HAVE_VECTOR_INTRINSICS 1
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
|
||||
#else
|
||||
bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
#endif
|
||||
|
||||
LLVMContext &C = M.getContext();
|
||||
|
||||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
|
||||
@ -220,6 +137,13 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
if (getenv("AFL_LLVM_ONLY_FSRV")) {
|
||||
|
||||
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
}
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "afl-llvm-pass" VERSION cRST
|
||||
@ -255,9 +179,6 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 9
|
||||
char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
|
||||
#endif
|
||||
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
|
||||
use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
|
||||
|
||||
@ -375,24 +296,12 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
int PrevLocVecSize = PowerOf2Ceil(PrevLocSize);
|
||||
if (ngram_size)
|
||||
PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize
|
||||
#if LLVM_VERSION_MAJOR >= 12
|
||||
,
|
||||
false
|
||||
#endif
|
||||
);
|
||||
if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize, false);
|
||||
#endif
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
int PrevCallerVecSize = PowerOf2Ceil(PrevCallerSize);
|
||||
if (ctx_k)
|
||||
PrevCallerTy = VectorType::get(IntLocTy, PrevCallerVecSize
|
||||
#if LLVM_VERSION_MAJOR >= 12
|
||||
,
|
||||
false
|
||||
#endif
|
||||
);
|
||||
if (ctx_k) PrevCallerTy = VectorType::get(IntLocTy, PrevCallerVecSize, false);
|
||||
#endif
|
||||
|
||||
/* Get globals for the SHM region and the previous location. Note that
|
||||
@ -530,11 +439,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ctx_k) {
|
||||
|
||||
PrevCaller = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PrevCallerTy,
|
||||
#endif
|
||||
AFLPrevCaller);
|
||||
PrevCaller = IRB.CreateLoad(PrevCallerTy, AFLPrevCaller);
|
||||
PrevCaller->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
PrevCtx =
|
||||
@ -547,11 +452,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
// load the context ID of the previous function and write to a
|
||||
// local variable on the stack
|
||||
LoadInst *PrevCtxLoad = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
IRB.getInt32Ty(),
|
||||
#endif
|
||||
AFLContext);
|
||||
LoadInst *PrevCtxLoad = IRB.CreateLoad(IRB.getInt32Ty(), AFLContext);
|
||||
PrevCtxLoad->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
PrevCtx = PrevCtxLoad;
|
||||
@ -625,11 +526,11 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
// cur_loc++;
|
||||
cur_loc = AFL_R(map_size);
|
||||
|
||||
/* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63).
|
||||
The inline function successors() is not inlined and also not found at runtime
|
||||
:-( As I am unable to detect Ubuntu18.04 here, the next best thing is to
|
||||
disable this optional optimization for LLVM 6.0.0 and Linux */
|
||||
#if !(LLVM_VERSION_MAJOR == 6 && LLVM_VERSION_MINOR == 0) || !defined __linux__
|
||||
/* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63).
|
||||
The inline function successors() is not inlined and also not found at
|
||||
runtime
|
||||
:-( As I am unable to detect Ubuntu18.04 here, the next best thing is
|
||||
to disable this optional optimization for LLVM 6.0.0 and Linux */
|
||||
// only instrument if this basic block is the destination of a previous
|
||||
// basic block that has multiple successors
|
||||
// this gets rid of ~5-10% of instrumentations that are unnecessary
|
||||
@ -674,11 +575,11 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
IRBuilder<> Post_IRB(Inst);
|
||||
|
||||
StoreInst *RestoreCtx;
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
if (ctx_k)
|
||||
RestoreCtx = IRB.CreateStore(PrevCaller, AFLPrevCaller);
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
|
||||
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
|
||||
MDNode::get(C, None));
|
||||
@ -691,8 +592,6 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ConstantInt *CurLoc;
|
||||
|
||||
#ifdef AFL_HAVE_VECTOR_INTRINSICS
|
||||
@ -708,19 +607,11 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
if (ngram_size) {
|
||||
|
||||
PrevLoc = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PrevLocTy,
|
||||
#endif
|
||||
AFLPrevLoc);
|
||||
PrevLoc = IRB.CreateLoad(PrevLocTy, AFLPrevLoc);
|
||||
|
||||
} else {
|
||||
|
||||
PrevLoc = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
IRB.getInt32Ty(),
|
||||
#endif
|
||||
AFLPrevLoc);
|
||||
PrevLoc = IRB.CreateLoad(IRB.getInt32Ty(), AFLPrevLoc);
|
||||
|
||||
}
|
||||
|
||||
@ -747,11 +638,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
/* Load SHM pointer */
|
||||
|
||||
LoadInst *MapPtr = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
PointerType::get(Int8Ty, 0),
|
||||
#endif
|
||||
AFLMapPtr);
|
||||
LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
|
||||
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
Value *MapPtrIdx;
|
||||
@ -764,20 +651,15 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
Int32Ty));
|
||||
else
|
||||
#endif
|
||||
MapPtrIdx = IRB.CreateGEP(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
Int8Ty,
|
||||
#endif
|
||||
MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
|
||||
MapPtrIdx =
|
||||
IRB.CreateGEP(Int8Ty, MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc));
|
||||
|
||||
/* Update bitmap */
|
||||
|
||||
if (use_threadsafe_counters) { /* Atomic */
|
||||
|
||||
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
llvm::MaybeAlign(1),
|
||||
#endif
|
||||
llvm::AtomicOrdering::Monotonic);
|
||||
/*
|
||||
|
||||
@ -787,22 +669,13 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
} else {
|
||||
|
||||
LoadInst *Counter = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
IRB.getInt8Ty(),
|
||||
#endif
|
||||
MapPtrIdx);
|
||||
LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx);
|
||||
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
Value *Incr = IRB.CreateAdd(Counter, One);
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 9
|
||||
if (!skip_nozero) {
|
||||
|
||||
#else
|
||||
if (neverZero_counters_str != NULL) {
|
||||
|
||||
#endif
|
||||
/* hexcoder: Realize a counter that skips zero during overflow.
|
||||
* Once this counter reaches its maximum value, it next increments to
|
||||
* 1
|
||||
@ -881,124 +754,6 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (use_threadsafe_counters) { /*Atomic NeverZero */
|
||||
// handle the list of registered blocks to instrument
|
||||
for (auto val : todo) {
|
||||
|
||||
/* hexcoder: Realize a thread-safe counter that skips zero during
|
||||
* overflow. Once this counter reaches its maximum value, it next
|
||||
* increments to 1
|
||||
*
|
||||
* Instead of
|
||||
* Counter + 1 -> Counter
|
||||
* we inject now this
|
||||
* Counter + 1 -> {Counter, OverflowFlag}
|
||||
* Counter + OverflowFlag -> Counter
|
||||
*/
|
||||
|
||||
/* equivalent c code looks like this
|
||||
* Thanks to
|
||||
https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/
|
||||
|
||||
int old = atomic_load_explicit(&Counter, memory_order_relaxed);
|
||||
int new;
|
||||
do {
|
||||
|
||||
if (old == 255) {
|
||||
|
||||
new = 1;
|
||||
|
||||
} else {
|
||||
|
||||
new = old + 1;
|
||||
|
||||
}
|
||||
|
||||
} while (!atomic_compare_exchange_weak_explicit(&Counter, &old, new,
|
||||
|
||||
memory_order_relaxed, memory_order_relaxed));
|
||||
|
||||
*/
|
||||
|
||||
Value * MapPtrIdx = val;
|
||||
Instruction * MapPtrIdxInst = cast<Instruction>(val);
|
||||
BasicBlock::iterator it0(&(*MapPtrIdxInst));
|
||||
++it0;
|
||||
IRBuilder<> IRB(&(*it0));
|
||||
|
||||
// load the old counter value atomically
|
||||
LoadInst *Counter = IRB.CreateLoad(
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
IRB.getInt8Ty(),
|
||||
#endif
|
||||
MapPtrIdx);
|
||||
Counter->setAlignment(llvm::Align());
|
||||
Counter->setAtomic(llvm::AtomicOrdering::Monotonic);
|
||||
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
BasicBlock *BB = IRB.GetInsertBlock();
|
||||
// insert a basic block with the corpus of a do while loop
|
||||
// the calculation may need to repeat, if atomic compare_exchange is not
|
||||
// successful
|
||||
|
||||
BasicBlock::iterator it(*Counter);
|
||||
it++; // split after load counter
|
||||
BasicBlock *end_bb = BB->splitBasicBlock(it);
|
||||
end_bb->setName("injected");
|
||||
|
||||
// insert the block before the second half of the split
|
||||
BasicBlock *do_while_bb =
|
||||
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
|
||||
|
||||
// set terminator of BB from target end_bb to target do_while_bb
|
||||
auto term = BB->getTerminator();
|
||||
BranchInst::Create(do_while_bb, BB);
|
||||
term->eraseFromParent();
|
||||
|
||||
// continue to fill instructions into the do_while loop
|
||||
IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt());
|
||||
|
||||
PHINode *PN = IRB.CreatePHI(Int8Ty, 2);
|
||||
|
||||
// compare with maximum value 0xff
|
||||
auto *Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1));
|
||||
|
||||
// increment the counter
|
||||
Value *Incr = IRB.CreateAdd(Counter, One);
|
||||
|
||||
// select the counter value or 1
|
||||
auto *Select = IRB.CreateSelect(Cmp, One, Incr);
|
||||
|
||||
// try to save back the new counter value
|
||||
auto *CmpXchg = IRB.CreateAtomicCmpXchg(
|
||||
MapPtrIdx, PN, Select, llvm::AtomicOrdering::Monotonic,
|
||||
llvm::AtomicOrdering::Monotonic);
|
||||
CmpXchg->setAlignment(llvm::Align());
|
||||
CmpXchg->setWeak(true);
|
||||
CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||
|
||||
// get the result of trying to update the Counter
|
||||
Value *Success =
|
||||
IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({1}));
|
||||
// get the (possibly updated) value of Counter
|
||||
Value *OldVal =
|
||||
IRB.CreateExtractValue(CmpXchg, ArrayRef<unsigned>({0}));
|
||||
|
||||
// initially we use Counter
|
||||
PN->addIncoming(Counter, BB);
|
||||
// on retry, we use the updated value
|
||||
PN->addIncoming(OldVal, do_while_bb);
|
||||
|
||||
// if the cmpXchg was not successful, retry
|
||||
IRB.CreateCondBr(Success, end_bb, do_while_bb);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1073,26 +828,6 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
return PreservedAnalyses();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */
|
||||
static void registerAFLPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLCoverage());
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterAFLPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerAFLPass);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);
|
||||
#endif
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user