mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-30 14:50:36 +00:00
21d4f173c5
1. Use optional[T] instead of array[T, 0:1]. 2. Deduplicate 3 copies of ARP packet. 3. Deduplicate IPOPT_LSRR/IPOPT_SSRR/IPOPT_RR. 4. More precise description of IPOPT_TIMESTAMP/IPOPT_LSRR/IPOPT_SSRR/IPOPT_RR. 5. Don't use IPOPT_END/IPOPT_NOOP in generic option (they have different format). 6. Restrict cipso doi values. 7. Fix IPOPT_RA value type (int16 instead of int32). 8. Match ipv4/ipv6 packet type with payload. 9. Prefer 0 frag_off for ipv4 packets (they are extremely hard to get right).
170 lines
5.2 KiB
Go
170 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 {
|
|
if csummedArg, ok := parentsMap[arg]; ok {
|
|
return csummedArg
|
|
}
|
|
panic(fmt.Sprintf("%v for %v is not in parents map", ParentRef, typ.Name()))
|
|
} else {
|
|
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 '%v' references non existent field '%v'", typ.FieldName(), 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 {
|
|
for _, field := range arg.Inner {
|
|
if field.Type().FieldName() == name {
|
|
return field
|
|
}
|
|
}
|
|
panic(fmt.Sprintf("failed to find %v field in %v", name, arg.Type().Name()))
|
|
}
|