一、ClusterFuzz 使用简介

根据 ClusterFuzz官方说明 ,可以在本地执行以下命令启动 ClusterFuzz 平台:

1
2
3
4
5
# If you run the server for the first time or want to reset all data.
python butler.py run_server --bootstrap

# In all the other cases, do not use "--bootstrap" flag.
python butler.py run_server

启动 ClusterFuzz 后,通过访问http://localhost:9000,即可打开 web 页面。

执行 fuzz 任务,需要启动 bot,命令如下:

1
python butler.py run_bot --name my-bot /path/to/my-bot  # rename my-bot to anything

当 bot 启动后,ClusterFuzz 的各项任务才能执行。

二、run_server 源码分析

当我们执行 python butler.py run_server --skip-install-deps --bootstrap 时,发生了什么?

sequenceDiagram
participant A as bulter.py
box local/bulter
participant B as run_server.py
participant C as common.py
end
box appengine
participant D as main.py
participant E as server.py
end
box clusterfuzz/_internal
participant F as test_utils.py
end
participant G as gcs.go

A ->> A: call _setup
A ->> B: call execute
B ->> B: call bootstrap_gcs
B ->> F: call start_cloud_emulator
F -->> B: start pubsub emulator and datastore emulator
B ->> G: go run gcs.go
alt bootstrap
    B ->> B: call bootstrap_db
end
B ->> B: call start_cron_threads
B ->> C: call execute_async
C ->> D: gunicorn start app for cron service
D ->> E: register_routes
E -->> D: return cron service app
B ->> C: call execute
C ->> D: gunicorn start app for dev service
D ->> E: register_routes
E -->> D: return dev service app</pre>
  • _setup:设置工程的模块搜索路径
  • run_server.execute:依次启动各项服务
    • bootstrap_gcs:创建 gcs 相关路径,默认保存在 local/storage/local_gcs 之下
    • test_utils.start_cloud_emulator:启动 pubsub emulator 和 datastore emulator
    • common.execute_async('go run emulators/gcs.go'):启动 gcs emulator
    • bootstrap_db:执行 src/local/butler/scripts/setup.py 中的execute,初始化数据库
    • start_cron_threads:启动定时任务,各项任务通过 route 转到相应 handler 执行
    • common.execute_async('gunicorn -b :{port} main:app):gunicorn 指定 port 启动 src/appengine/main.py 中的 app 应用
    • src/appengine/main.py:调用 server.py 中的 app
    • src/appengine/server.py:定义 web app,注册 web route 信息

三、run_bot 源码分析

当我们执行 python butler.py run_bot --name fuzz-bot fuzz-bot/ 时,发生了什么?

sequenceDiagram
participant A as bulter.py
box local/bulter
participant B as run_bot.py
participant C as common.py
end
box python/bot
participant D as startup/run_bot.py
end
box local/_internal
participant E as metrics/monitor.py
participant F as bot/fuzzers/init.py
participant G as bot/tasks/update_task.py
participant H as base/tasks.py
participant I as bot/tasks/commands.py
end

A ->> A: call _setup
A ->> B: call execute
B ->> B: call _setup_bot_directory
B ->> B: call _setup_environment_and_configs
B ->> C: call execute_async
C ->> D: start bot
D ->> E: initialize monitor
E -->> D: 
D ->> F: initialize fuzzer engine
F --> D: 
loop task_loop
    D ->> G: call run to update task
    G --> D: 
    D ->> H: call get_task
    H --> D: 
    D --> I: call process_commands to execute task
end</pre>
  • _setup:设置工程的模块搜索路径
  • run_bot.execute:启动 bot
    • _setup_bot_directory:创建 bot 相关路径
    • _setup_environment_and_configs:设置运行环境,如环境变量等
    • execute_async('python src/python/bot/startup/run_bot.py'):启动 bot
      • monitor.initialize:初始化监控器
      • fuzzers_init.run:初始化 fuzz 引擎,通过 import clusterfuzz._internal.bot.fuzzers.{engine_name}.engine 导入各 fuzzer 模块
      • task_loop:循环执行任务
        • update_task.run:更新任务信息和 bot 心跳
        • tasks.get_task:获取任务,有多种任务,fuzz 只是其中一种任务
        • commands.process_command:通过命令行执行任务