mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-26 21:00:30 +00:00
58da4c35b1
Remvoe FieldName from Type and add a separate Field type that holds field name. Use Field for struct fields, union options and syscalls arguments, only these really have names. Reduces size of sys/linux/gen/amd64.go from 5665583 to 5201321 (-8.2%). Allows to not create new type for squashed any pointer. But main advantages will follow, e.g. removing StructDesc, using TypeRef in Arg, etc. Update #1580
171 lines
5.2 KiB
Go
171 lines
5.2 KiB
Go
// Copyright 2017 syzkaller project authors. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
package prog
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
type CsumChunkKind int
|
|
|
|
const (
|
|
CsumChunkArg CsumChunkKind = iota
|
|
CsumChunkConst
|
|
)
|
|
|
|
type CsumInfo struct {
|
|
Kind CsumKind
|
|
Chunks []CsumChunk
|
|
}
|
|
|
|
type CsumChunk struct {
|
|
Kind CsumChunkKind
|
|
Arg Arg // for CsumChunkArg
|
|
Value uint64 // for CsumChunkConst
|
|
Size uint64 // for CsumChunkConst
|
|
}
|
|
|
|
func calcChecksumsCall(c *Call) (map[Arg]CsumInfo, map[Arg]struct{}) {
|
|
var inetCsumFields, pseudoCsumFields []Arg
|
|
|
|
// Find all csum fields.
|
|
ForeachArg(c, func(arg Arg, _ *ArgCtx) {
|
|
if typ, ok := arg.Type().(*CsumType); ok {
|
|
switch typ.Kind {
|
|
case CsumInet:
|
|
inetCsumFields = append(inetCsumFields, arg)
|
|
case CsumPseudo:
|
|
pseudoCsumFields = append(pseudoCsumFields, arg)
|
|
default:
|
|
panic(fmt.Sprintf("unknown csum kind %v", typ.Kind))
|
|
}
|
|
}
|
|
})
|
|
|
|
if len(inetCsumFields) == 0 && len(pseudoCsumFields) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
// Build map of each field to its parent struct.
|
|
parentsMap := make(map[Arg]Arg)
|
|
ForeachArg(c, func(arg Arg, _ *ArgCtx) {
|
|
if _, ok := arg.Type().(*StructType); ok {
|
|
for _, field := range arg.(*GroupArg).Inner {
|
|
parentsMap[InnerArg(field)] = arg
|
|
}
|
|
}
|
|
})
|
|
|
|
csumMap := make(map[Arg]CsumInfo)
|
|
csumUses := make(map[Arg]struct{})
|
|
|
|
// Calculate generic inet checksums.
|
|
for _, arg := range inetCsumFields {
|
|
typ, _ := arg.Type().(*CsumType)
|
|
csummedArg := findCsummedArg(arg, typ, parentsMap)
|
|
csumUses[csummedArg] = struct{}{}
|
|
chunk := CsumChunk{CsumChunkArg, csummedArg, 0, 0}
|
|
csumMap[arg] = CsumInfo{Kind: CsumInet, Chunks: []CsumChunk{chunk}}
|
|
}
|
|
|
|
// No need to continue if there are no pseudo csum fields.
|
|
if len(pseudoCsumFields) == 0 {
|
|
return csumMap, csumUses
|
|
}
|
|
|
|
// Extract ipv4 or ipv6 source and destination addresses.
|
|
var ipSrcAddr, ipDstAddr Arg
|
|
ForeachArg(c, func(arg Arg, _ *ArgCtx) {
|
|
groupArg, ok := arg.(*GroupArg)
|
|
if !ok {
|
|
return
|
|
}
|
|
// syz_csum_* structs are used in tests
|
|
switch groupArg.Type().TemplateName() {
|
|
case "ipv4_header", "syz_csum_ipv4_header":
|
|
ipSrcAddr, ipDstAddr = extractHeaderParams(groupArg, 4)
|
|
case "ipv6_packet_t", "syz_csum_ipv6_header":
|
|
ipSrcAddr, ipDstAddr = extractHeaderParams(groupArg, 16)
|
|
}
|
|
})
|
|
if ipSrcAddr == nil || ipDstAddr == nil {
|
|
panic("no ipv4 nor ipv6 header found")
|
|
}
|
|
|
|
// Calculate pseudo checksums.
|
|
for _, arg := range pseudoCsumFields {
|
|
typ, _ := arg.Type().(*CsumType)
|
|
csummedArg := findCsummedArg(arg, typ, parentsMap)
|
|
protocol := uint8(typ.Protocol)
|
|
var info CsumInfo
|
|
if ipSrcAddr.Size() == 4 {
|
|
info = composePseudoCsumIPv4(csummedArg, ipSrcAddr, ipDstAddr, protocol)
|
|
} else {
|
|
info = composePseudoCsumIPv6(csummedArg, ipSrcAddr, ipDstAddr, protocol)
|
|
}
|
|
csumMap[arg] = info
|
|
csumUses[csummedArg] = struct{}{}
|
|
csumUses[ipSrcAddr] = struct{}{}
|
|
csumUses[ipDstAddr] = struct{}{}
|
|
}
|
|
|
|
return csumMap, csumUses
|
|
}
|
|
|
|
func findCsummedArg(arg Arg, typ *CsumType, parentsMap map[Arg]Arg) Arg {
|
|
if typ.Buf == ParentRef {
|
|
csummedArg := parentsMap[arg]
|
|
if csummedArg == nil {
|
|
panic(fmt.Sprintf("%q for %q is not in parents map", ParentRef, typ.Name()))
|
|
}
|
|
return csummedArg
|
|
}
|
|
for parent := parentsMap[arg]; parent != nil; parent = parentsMap[parent] {
|
|
// TODO(dvyukov): support template argument names as in size calculation.
|
|
if typ.Buf == parent.Type().Name() {
|
|
return parent
|
|
}
|
|
}
|
|
panic(fmt.Sprintf("csum field %q references non existent field %q", typ.Name(), typ.Buf))
|
|
}
|
|
|
|
func composePseudoCsumIPv4(tcpPacket, srcAddr, dstAddr Arg, protocol uint8) CsumInfo {
|
|
info := CsumInfo{Kind: CsumInet}
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, srcAddr, 0, 0})
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, dstAddr, 0, 0})
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkConst, nil, uint64(swap16(uint16(protocol))), 2})
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkConst, nil, uint64(swap16(uint16(tcpPacket.Size()))), 2})
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, tcpPacket, 0, 0})
|
|
return info
|
|
}
|
|
|
|
func composePseudoCsumIPv6(tcpPacket, srcAddr, dstAddr Arg, protocol uint8) CsumInfo {
|
|
info := CsumInfo{Kind: CsumInet}
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, srcAddr, 0, 0})
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, dstAddr, 0, 0})
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkConst, nil, uint64(swap32(uint32(tcpPacket.Size()))), 4})
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkConst, nil, uint64(swap32(uint32(protocol))), 4})
|
|
info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, tcpPacket, 0, 0})
|
|
return info
|
|
}
|
|
|
|
func extractHeaderParams(arg *GroupArg, size uint64) (Arg, Arg) {
|
|
srcAddr := getFieldByName(arg, "src_ip")
|
|
dstAddr := getFieldByName(arg, "dst_ip")
|
|
if srcAddr.Size() != size || dstAddr.Size() != size {
|
|
panic(fmt.Sprintf("src/dst_ip fields in %v must be %v bytes", arg.Type().Name(), size))
|
|
}
|
|
return srcAddr, dstAddr
|
|
}
|
|
|
|
func getFieldByName(arg *GroupArg, name string) Arg {
|
|
typ := arg.Type().(*StructType)
|
|
for i, field := range arg.Inner {
|
|
if typ.Fields[i].Name == name {
|
|
return field
|
|
}
|
|
}
|
|
panic(fmt.Sprintf("failed to find %v field in %v", name, arg.Type().Name()))
|
|
}
|