一、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
  • _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
  • _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:通过命令行执行任务