首页
论坛
课程
招聘
[原创]syzkaller源码分析(一) syz-manager.go
2021-6-20 17:19 6272

[原创]syzkaller源码分析(一) syz-manager.go

2021-6-20 17:19
6272

关于syzkaller的资料以安装居多,代码分析比较少,把自己的关于代码的理解稍微写一下,有理解错误的函数也请指正。下面内容主要就是syz-manager.go的主要流程,去掉了对核心流程不重要的部分以及具体实现,要是了解具体的实现还要去看源码。源码地址如下:https://github.com/google/syzkaller

 

md文件会附在最后

 

对syzkaller的简介可以去看 https://xz.aliyun.com/t/5079

 

syzkaller正常情况下都以syz-manager作为入口,syz-manager.go主要负责各种工作的启动(HTTP、RPC、dashboard等等)、调用fuzz以及repro的生成。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
manager.go
 
func main() {
    RunManager(cfg)
}
 
func RunManager(cfg *mgrconfig.Config) {
    初始化: 文件 corpus.db &Manager HTTP RPC prometheus参数 dash
    go func() {
        log()
    }
 
    if *flagBench != ""  //bench: write execution statistics into this file periodically
        go func(){
            mgr.minimizeCorpus()
            写入文件
        }
 
    if mgr.dash != nil {
        go mgr.dashboardReporter()
    }
    mgr.vmLoop()
}
 
func (mgr *Manager) vmLoop() {
        启动instance
        初始化pendingRepro reproducing reproInstances
 
        //可以复现并且有剩余的instances
        for canRepro() && len(instances) >= instancesPerRepro {
            go func() {
                repro.Run()
            }
        }
 
        //没有可以复现的但是有剩余的instances
        for !canRepro() && len(instances) != 0 {
            go func(){
                //调用mgr.runInstanceInner;
                //mgr.runInstanceInner()调用了FuzzerCmd()启动fuzz; 有调用MonitorExecution()监控信息并返回Report对象
                //返回crash信息
                mgr.runInstance(idx)
            }
        }
        // 下面进行结果处理
        ...
    }
}

重点函数 minimizeCorpus()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func (mgr *Manager) minimizeCorpus() {
    ...
 
    //返回的signal有elemType相同的,取其中prio最高的
    for _, ctx := range signal.Minimize(inputs) {
        ...
    }
    ...
 
    //为了防止出现corpus explosion,需要统计call的cov和count情况
    for call, info := range mgr.collectSyscallInfoUnlocked() {
        if 出现corpus explosion情况
            mgr.saturatedCalls[call] = true
    }
    写回db.filename
}

重点函数repro.Run()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func Run(){
    ParseLog(crashLog) //返回[]*LogEntry  LogEntry describes one program in execution log.
    设置各种参数
    go func(){
        启动vmIndex个Instance
    }
 
    //最主要的函数
    //见下面
    res, err := ctx.repro(entries, crashStart)
 
    //Try to rerun the repro if the report is corrupted.
    //Corrupted indicates whether the report is truncated of corrupted in some other way.
    for attempts := 0; ctx.report.Corrupted && attempts < 3; attempts++ {
        if res.CRepro {
            _, err = ctx.testCProg(res.Prog, res.Duration, res.Opts)
        } else {
            _, err = ctx.testProg(res.Prog, res.Duration, res.Opts)
    }
        if err != nil {
            return nil, nil, err
        }
    }
}

重点函数 ctx.repro

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
func (ctx *context) repro(){
    // Cut programs that were executed after crash.
    //发生crash后面的prog就不需要了
    for i, ent := range entries {
        if ent.Start > crashStart {
        entries = entries[:i]
        break
        }
    }
 
    //返回值是能触发crash的单个program或者能触发crash的programs的组合
    //首先,在所有program(用entries数组表示)提取出每个proc所执行的最后一个program,
    //并按执行先后倒序排列,存放到lastEntries数组中。
    //其次,调用extractProgSingle()倒序执行每一个program,如果res不为空,返回
    //最后(即单个程序不会引起crash),调用extractProgBisect()测试哪几个program一起触发了crash
    //extractProgBisect()的实现:先调用bisectProgs()进行分组,看哪一组可以触发crash。
    ctx.extractProg(entries)
 
    //主要调用prog.Minimize(),Minimize calls and arguments
    // prog.Minimize()的原始注释如下:
    // Minimize minimizes program p into an equivalent program using the equivalence
    // predicate pred. It iteratively generates simpler programs and asks pred
    // whether it is equal to the original program or not. If it is equivalent then
    // the simplification attempt is committed and the process continues.
    ctx.minimizeProg(res)
 
    // Try extracting C repro without simplifying options first.
    // Try triggering crash with a C reproducer.
    // 调用ctx.testCProg()看能不能返回crashed=true,再进行赋值res.CRepro = crashed
    ctx.extractC(res)
 
    // Simplify options and try extracting C repro.
    //在repro.go中定义了progSimplifies数组作为简化规则,依次使用每一条规则后,如果有效(crash还能被触发),
    //再调用extractC(res)尝试提取C repro
    if !res.CRepro {
        ctx.simplifyProg(res)
    }
 
    // Simplify C related options.  
    //跟上面的ctx.simplifyProg(res)差不多,就是规则使用了cSimplifies数组
    if res.CRepro {
        ctx.simplifyC(res)
    }
}

[2022冬季班]《安卓高级研修班(网课)》月薪三万班招生中~

上传的附件:
收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回