系统调用对:目标系统调用->相关系统调用们
type CallPairMap map[int][]int
在启动Manager时会对系统调用对信息进行初始化。
CallPairFromFile函数会将指定文件中的信息转化为CallPairMap格式的系统调用对:
// RawCallPair用string来描述系统调用对
type RawCallPair struct {
Target string
Relate []string
}
// 初始化CallPairMap,从json文件读取Tcall和Rcalls,并转化为CallPairMap格式
func CallPairFromFile(filename string, target *Target) CallPairMap {
// 先将json转化成[]RawCallPair,Tcall和Rcall都用string来表示
b, err := ioutil.ReadFile(filename)
var rawCallPairs []RawCallPair
err = json.Unmarshal(b, &rawCallPairs)
// 将[]RawCallPair转化成tmpCallMap,Tcall和Rcall由用string表示转化成用ID表示,并用map去重
tmpCallMap := make(map[int]map[int]bool, len(rawCallPairs))
for _, rawCallPair := range rawCallPairs {
tcalls := str2Calls(rawCallPair.Target)
for _, tcall := range tcalls {
rcallMap := tmpCallMap[tcall]
if rcallMap == nil {
rcallMap = make(map[int]bool, len(rawCallPair.Relate))
tmpCallMap[tcall] = rcallMap
}
for _, rawRCall := range rawCallPair.Relate {
for _, rc := range str2Calls(rawRCall) {
rcallMap[rc] = true
}
}
}
}
// 将tmpCallMap转化成CallPairMap,将map转换成[],并排序
callPairMap := make(CallPairMap, len(tmpCallMap))
for tcall, rcallMap := range tmpCallMap {
keys := make([]int, 0, len(rcallMap))
for k := range rcallMap {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
return keys[i] < keys[j]
})
callPairMap[tcall] = keys
}
return callPairMap
}
CallPairMap是Manager结构体的一个成员变量,通过追踪CallPairFromFile函数,发现在启动Manager时,在RunManager函数中调用了CallPairFromFile函数。
在对语料库和选择表初始化时,会读系统调用对信息。
因为语料库中的程序必须包含目标系统调用,所以在初始化语料库时,会通过rawTcalls检查程序是否包含目标系统调用,起到筛选的作用;
通过GetRawTargetCalls函数读CallPairMap,获取rawTcalls,即只保留目标系统调用。
// 获得Tcalls
// 将CallPairMap类型的cpMap转化成map[int]bool类型的rawTcalls,即只保留Tcall
func (cpMap CallPairMap) GetRawTargetCalls(target *Target) map[int]bool {
rawTcalls := make(map[int]bool, len(cpMap))
for tcall := range cpMap {
// 处理带有 "_rf1" 或 "$tmp_rf1" 后缀的变异调用
callName := target.Syscalls[tcall].Name
if strings.HasSuffix(callName, "_rf1") {
// 将变异调用还原为原始调用
oriName := callName[:len(callName)-4]
if strings.HasSuffix(callName, "$tmp_rf1") {
oriName = callName[:len(callName)-8]
}
rawTcalls[target.SyscallMap[oriName].ID] = true
} else {
rawTcalls[tcall] = true
}
}
return rawTcalls
}
选择表的构建分两步:1.初始化系统调用(和syzkaller相同),2.初始化系统调用对信息(syzdirect特有)。
系统调用对信息的初始化由EnableGo函数完成:
// 选择表中系统调用对信息的存储形式是CallPairInfo数组
type CallPairInfo struct {
Tcall int
Rcall int
Dists []uint32
Prio int
}
// 依照CallPairMap(静态)和rpcCallPairMap(动态,包含dist)来对ChoiceTable的CallPairSelector做初始化
func (ct *ChoiceTable) EnableGo(cpMap CallPairMap, rpcCPMap RpcCallPairMap, corpus []*Prog, startTime time.Time, hitIndex uint32) {
// 初始化 CallPairInfo 列表和infoIdxMap索引映射
cpInfos := make([]CallPairInfo, 0, len(cpMap)*3)
infoIdxMap := make(map[int]map[int]int, len(cpMap))
allPrio := 0
// 遍历CallPairMap的所有调用对(Tcall → []Rcall)
for tcall, rcalls := range cpMap {
if !ct.Enabled(tcall) {
continue
}
rpcRcallMap, ok1 := rpcCPMap[tcall]
tmp := append(rcalls, -1)
rIdxMap := make(map[int]int)
// 处理每个Rcall(包括无关联调用 Rcall=-1)
for _, rcall := range tmp {
if rcall != -1 && !ct.Enabled(rcall) {
continue
}
hasAdd := false
if ok1 {
// 从 rpcCallPairMap 加载历史距离数据(如有)
if dists2, ok2 := rpcRcallMap[rcall]; ok2 {
prio := distance2Prio(calcDistSum(dists2), len(dists2))
cpInfos = append(cpInfos, CallPairInfo{
Tcall: tcall,
Rcall: rcall,
Prio: prio,
Dists: dists2,
})
allPrio += prio
hasAdd = true
}
}
// 默认优先级(无历史数据时),有关联prio=1,无关联prio=0
if !hasAdd {
prio := 1
if rcall == -1 {
prio = 0
}
cpInfos = append(cpInfos, CallPairInfo{
Tcall: tcall,
Rcall: rcall,
Prio: prio,
Dists: make([]uint32, 0, 5),
})
allPrio += prio
}
rIdxMap[rcall] = len(cpInfos) - 1
}
// targetCalls = append(targetCalls, tcall)
infoIdxMap[tcall] = rIdxMap
}
if len(cpInfos) == 0 {
panic("all target calls are disabled")
}
// 更新ChoiceTable中的CallPairSelector
ct.GoEnable = true
ct.startTime = startTime
ct.CallPairSelector.hitIndex = hitIndex
ct.CallPairSelector.callPairInfos = cpInfos
ct.CallPairSelector.prioSum = allPrio
ct.CallPairSelector.infoIdxMap = infoIdxMap
}