使用afl fuzz pdfium

下载源码

先在 https://pdfium.googlesource.com/pdfium/ 下载源码.

1
2
3
4
5
mkdir repo
cd repo
gclient config --unmanaged https://pdfium.googlesource.com/pdfium.git
gclient sync
cd pdfium

gclient 命令在 depot_tools 中, 需要安装 参考下面的文章

http://www.chromium.org/developers/how-tos/install-depot-tools

1
2
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=`pwd`/depot_tools:"$PATH"

gclient sync 同步时需要fq,可以简单的使用环境变量的方法解决。

https_proxy=http://localhost:8118 gclient sync 下载 download google storage过
程中还会遇到一个网络问题,需要编写配置文件 ~/.boto

1
2
3
[Boto]
proxy = 127.0.0.1 # 不带 http://
proxy_port= 8118

export NO_AUTH_BOTO_CONFIG=~/.boto

源码包非常大,大概有1G多,需要耐心等待。

编译

编译需要使用 ubuntu 或者 Debian 系统,其他系统的依赖问题解决起来比较麻烦,
如果是上面两种操作系统的话,有脚本自动安装依赖。

./build/install-build-deps.sh

安装完所有依赖后就可以开始编译了,首先要先生成 gn 文件 (2016 年google 放弃使用原来的 gyp 编译方式)

gn args out/afl 会调用vim 编译器, 输入下面的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# Build arguments go here.
# See "gn args <out_dir> --list" for available build arguments.
use_goma = false # Googlers only. Make sure goma is installed and running first.
is_debug = false # Enable debugging features.

pdf_use_skia = true # Set true to enable experimental skia backend.
pdf_use_skia_paths = false # Set true to enable experimental skia backend (paths only).

pdf_enable_xfa = true # Set false to remove XFA support (implies JS support).
pdf_enable_v8 = true # Set false to remove Javascript support.
pdf_is_standalone = true # Set for a non-embedded build.
is_component_build = false # Disable component build (must be false)
v8_static_library = true

clang_use_chrome_plugins = false # Currently must be false.
use_sysroot = false # Currently must be false on Linux, but entirely omitted on windows.

use_afl = true
#is_asan = true
enable_nacl = true
optimize_for_fuzzing = true
symbol_level=1

要编译生成 pdfium_test, 必须指定 pdf_is_standalone = true, 执行 ninjia -C out/afl pdfium_test

接下来要解决 afl 的问题了, pdfium 的 third_party中不包含 afl-fuzz 的源代码,需要到 chromium.googlesource.com 项目下载。
chromium 项目支持 libfuzzer 和 afl-fuzz,只要使用开关, use_libfuzzer = true
或者 use_afl = true 即可打开。

https://chromium.googlesource.com/chromium/src/third_party/+/master/afl/

可以直接下载 tgz 文件 https://chromium.googlesource.com/chromium/src/third_party/+archive/master/afl.tar.gz
下载后将源码 copy 到 ~/repo/pdfium/third_party/afl 中, 使用 ninja -C out/afl 编译整个项目。

使用 is_debug=false 可以明显提高fuzzing 速度,应该开启。另外一个比较有用的是
symbol_level, 设置 symbol_level=1 可以添加必要的调试符号,便于gdb调试。

在编译 skia backend 支持时,需要额外处理, 使用 C++14

1
use_cxx11 = false

afl-fuzz

随着 chromium 代码的更新, afl 源码编译出现了一些小问题,需要处理。

src/third_party/afl/patches/0001-fix-build-with-std-c11.patch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
diff --git a/afl-fuzz.c b/afl-fuzz.c
index 01b4afef0ecc..f0d564a33037 100644
--- a/afl-fuzz.c
+++ b/afl-fuzz.c
@@ -23,7 +23,9 @@
#define AFL_MAIN
#define MESSAGES_TO_STDOUT

+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#define _FILE_OFFSET_BITS 64

#include "config.h"
diff --git a/types.h b/types.h
index 784d3a7a286d..d24d1fdd97e8 100644
--- a/types.h
+++ b/types.h
@@ -78,7 +78,7 @@ typedef int64_t s64;
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)

#define MEM_BARRIER() \
- asm volatile("" ::: "memory")
+ __asm__ volatile("" ::: "memory")

#define likely(_x) __builtin_expect(!!(_x), 1)
#define unlikely(_x) __builtin_expect(!!(_x), 0)

afl-fuzz 的使用和其他项目一样。初始的种子文件有几个地方可以获取:

./afl-fuzz -M 01 -m 1024 -i /home/henices/input -o /home/henices/out -x /tmp/pdf.dict -- ./pdfium_test @@

参考资料