mirror of
https://github.com/reactos/syzkaller.git
synced 2025-02-14 00:13:23 +00:00
sys: add proc type to denote per proccess integers
This commit is contained in:
parent
16491e22d5
commit
253a40f30d
@ -142,6 +142,9 @@ func parse(data []byte) (*Config, map[int]bool, []*regexp.Regexp, error) {
|
||||
if cfg.Procs <= 0 {
|
||||
cfg.Procs = 1
|
||||
}
|
||||
if cfg.Procs > 32 {
|
||||
return nil, nil, nil, fmt.Errorf("config param procs has higher value '%v' then the max supported 32", cfg.Procs)
|
||||
}
|
||||
if cfg.Output == "" {
|
||||
if cfg.Type == "local" {
|
||||
cfg.Output = "none"
|
||||
|
@ -29,7 +29,7 @@ type Options struct {
|
||||
}
|
||||
|
||||
func Write(p *prog.Prog, opts Options) ([]byte, error) {
|
||||
exec := p.SerializeForExec()
|
||||
exec := p.SerializeForExec(0)
|
||||
w := new(bytes.Buffer)
|
||||
|
||||
fmt.Fprint(w, "// autogenerated by syzkaller (http://github.com/google/syzkaller)\n\n")
|
||||
|
@ -31,6 +31,7 @@ type Env struct {
|
||||
bin []string
|
||||
timeout time.Duration
|
||||
flags uint64
|
||||
pid int
|
||||
|
||||
StatExecs uint64
|
||||
StatRestarts uint64
|
||||
@ -85,7 +86,7 @@ func DefaultFlags() (uint64, time.Duration, error) {
|
||||
return flags, *flagTimeout, nil
|
||||
}
|
||||
|
||||
func MakeEnv(bin string, timeout time.Duration, flags uint64) (*Env, error) {
|
||||
func MakeEnv(bin string, timeout time.Duration, flags uint64, pid int) (*Env, error) {
|
||||
// IPC timeout must be larger then executor timeout.
|
||||
// Otherwise IPC will kill parent executor but leave child executor alive.
|
||||
if timeout < 7*time.Second {
|
||||
@ -121,6 +122,7 @@ func MakeEnv(bin string, timeout time.Duration, flags uint64) (*Env, error) {
|
||||
bin: strings.Split(bin, " "),
|
||||
timeout: timeout,
|
||||
flags: flags,
|
||||
pid: pid,
|
||||
}
|
||||
if len(env.bin) == 0 {
|
||||
return nil, fmt.Errorf("binary is empty string")
|
||||
@ -159,7 +161,7 @@ func (env *Env) Close() error {
|
||||
func (env *Env) Exec(p *prog.Prog) (output []byte, cov [][]uint32, errnos []int, failed, hanged bool, err0 error) {
|
||||
if p != nil {
|
||||
// Copy-in serialized program.
|
||||
progData := p.SerializeForExec()
|
||||
progData := p.SerializeForExec(env.pid)
|
||||
if len(progData) > len(env.In) {
|
||||
panic("program is too long")
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ func TestEmptyProg(t *testing.T) {
|
||||
bin := buildExecutor(t)
|
||||
defer os.Remove(bin)
|
||||
|
||||
env, err := MakeEnv(bin, timeout, 0)
|
||||
env, err := MakeEnv(bin, timeout, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create env: %v", err)
|
||||
}
|
||||
@ -82,7 +82,7 @@ func TestExecute(t *testing.T) {
|
||||
flags := []uint64{0, FlagThreaded, FlagThreaded | FlagCollide}
|
||||
for _, flag := range flags {
|
||||
t.Logf("testing flags 0x%x\n", flag)
|
||||
env, err := MakeEnv(bin, timeout, flag)
|
||||
env, err := MakeEnv(bin, timeout, flag, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create env: %v", err)
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ const (
|
||||
dataOffset = 512 << 20
|
||||
)
|
||||
|
||||
func (p *Prog) SerializeForExec() []byte {
|
||||
func (p *Prog) SerializeForExec(pid int) []byte {
|
||||
if err := p.validate(); err != nil {
|
||||
panic(fmt.Errorf("serializing invalid program: %v", err))
|
||||
}
|
||||
@ -72,7 +72,7 @@ func (p *Prog) SerializeForExec() []byte {
|
||||
if arg1.Type.Dir() != sys.DirOut {
|
||||
w.write(ExecInstrCopyin)
|
||||
w.write(physicalAddr(arg) + w.args[arg1].Offset)
|
||||
w.writeArg(arg1)
|
||||
w.writeArg(arg1, pid)
|
||||
instrSeq++
|
||||
}
|
||||
}
|
||||
@ -83,7 +83,7 @@ func (p *Prog) SerializeForExec() []byte {
|
||||
w.write(uintptr(c.Meta.ID))
|
||||
w.write(uintptr(len(c.Args)))
|
||||
for _, arg := range c.Args {
|
||||
w.writeArg(arg)
|
||||
w.writeArg(arg, pid)
|
||||
}
|
||||
w.args[c.Ret] = &argInfo{Idx: instrSeq}
|
||||
instrSeq++
|
||||
@ -143,12 +143,12 @@ func (w *execContext) write(v uintptr) {
|
||||
w.buf = append(w.buf, byte(v>>0), byte(v>>8), byte(v>>16), byte(v>>24), byte(v>>32), byte(v>>40), byte(v>>48), byte(v>>56))
|
||||
}
|
||||
|
||||
func (w *execContext) writeArg(arg *Arg) {
|
||||
func (w *execContext) writeArg(arg *Arg, pid int) {
|
||||
switch arg.Kind {
|
||||
case ArgConst:
|
||||
w.write(ExecArgConst)
|
||||
w.write(arg.Size())
|
||||
w.write(arg.Value())
|
||||
w.write(arg.Value(pid))
|
||||
case ArgResult:
|
||||
w.write(ExecArgResult)
|
||||
w.write(arg.Size())
|
||||
|
@ -16,7 +16,7 @@ func TestSerializeForExecRandom(t *testing.T) {
|
||||
rs, iters := initTest(t)
|
||||
for i := 0; i < iters; i++ {
|
||||
p := Generate(rs, 10, nil)
|
||||
p.SerializeForExec()
|
||||
p.SerializeForExec(i % 16)
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,7 +159,7 @@ func TestSerializeForExec(t *testing.T) {
|
||||
t.Fatalf("failed to deserialize prog %v: %v", i, err)
|
||||
}
|
||||
t.Run(fmt.Sprintf("%v:%v", i, p.String()), func(t *testing.T) {
|
||||
data := p.SerializeForExec()
|
||||
data := p.SerializeForExec(i % 16)
|
||||
w := new(bytes.Buffer)
|
||||
binary.Write(w, binary.LittleEndian, test.serialized)
|
||||
if !bytes.Equal(data, w.Bytes()) {
|
||||
|
@ -69,7 +69,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
|
||||
baseSize = base.Res.Size()
|
||||
}
|
||||
switch a := arg.Type.(type) {
|
||||
case *sys.IntType, *sys.FlagsType, *sys.ResourceType, *sys.VmaType:
|
||||
case *sys.IntType, *sys.FlagsType, *sys.ResourceType, *sys.VmaType, *sys.ProcType:
|
||||
arg1, calls1 := r.generateArg(s, arg.Type)
|
||||
p.replaceArg(c, arg, arg1, calls1)
|
||||
case *sys.BufferType:
|
||||
@ -326,7 +326,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred func(*Prog, int) bool, crash bool)
|
||||
return true
|
||||
}
|
||||
}
|
||||
case *sys.IntType, *sys.FlagsType, *sys.ResourceType:
|
||||
case *sys.IntType, *sys.FlagsType, *sys.ResourceType, *sys.ProcType:
|
||||
// TODO: try to reset bits in ints
|
||||
// TODO: try to set separate flags
|
||||
if crash {
|
||||
|
@ -101,8 +101,6 @@ func calcStaticPriorities() [][]float32 {
|
||||
noteUsage(1.0, "signalno")
|
||||
case sys.IntInaddr:
|
||||
noteUsage(1.0, "inaddr")
|
||||
case sys.IntInport:
|
||||
noteUsage(1.0, "inport")
|
||||
default:
|
||||
panic("unknown int kind")
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ func encodeValue(value, size uintptr, bigEndian bool) uintptr {
|
||||
}
|
||||
|
||||
// Returns value taking endianness into consideration.
|
||||
func (a *Arg) Value() uintptr {
|
||||
func (a *Arg) Value(pid int) uintptr {
|
||||
switch typ := a.Type.(type) {
|
||||
case *sys.IntType:
|
||||
return encodeValue(a.Val, typ.Size(), typ.BigEndian)
|
||||
@ -95,6 +95,9 @@ func (a *Arg) Value() uintptr {
|
||||
return encodeValue(a.Val, typ.Size(), typ.BigEndian)
|
||||
case *sys.LenType:
|
||||
return encodeValue(a.Val, typ.Size(), typ.BigEndian)
|
||||
case *sys.ProcType:
|
||||
val := uintptr(typ.ValuesStart) + uintptr(typ.ValuesPerProc) * uintptr(pid) + a.Val
|
||||
return encodeValue(val, typ.Size(), typ.BigEndian)
|
||||
}
|
||||
return a.Val
|
||||
}
|
||||
@ -102,7 +105,7 @@ func (a *Arg) Value() uintptr {
|
||||
func (a *Arg) Size() uintptr {
|
||||
switch typ := a.Type.(type) {
|
||||
case *sys.IntType, *sys.LenType, *sys.FlagsType, *sys.ConstType,
|
||||
*sys.ResourceType, *sys.VmaType, *sys.PtrType:
|
||||
*sys.ResourceType, *sys.VmaType, *sys.PtrType, *sys.ProcType:
|
||||
return typ.Size()
|
||||
case *sys.BufferType:
|
||||
return uintptr(len(a.Data))
|
||||
|
@ -634,7 +634,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call)
|
||||
// output arguments (their elements can be referenced in subsequent calls).
|
||||
switch typ.(type) {
|
||||
case *sys.IntType, *sys.FlagsType, *sys.ConstType,
|
||||
*sys.ResourceType, *sys.VmaType:
|
||||
*sys.ResourceType, *sys.VmaType, *sys.ProcType:
|
||||
return constArg(typ, typ.Default()), nil
|
||||
}
|
||||
}
|
||||
@ -720,8 +720,6 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call)
|
||||
v %= 130
|
||||
case sys.IntInaddr:
|
||||
v = uintptr(r.inaddr(s))
|
||||
case sys.IntInport:
|
||||
v = uintptr(r.inport(s))
|
||||
case sys.IntFileoff:
|
||||
r.choose(
|
||||
90, func() { v = 0 },
|
||||
@ -732,6 +730,8 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call)
|
||||
v = r.randRangeInt(a.RangeBegin, a.RangeEnd)
|
||||
}
|
||||
return constArg(a, v), nil
|
||||
case *sys.ProcType:
|
||||
return constArg(a, r.rand(int(a.ValuesPerProc))), nil
|
||||
case *sys.ArrayType:
|
||||
count := uintptr(0)
|
||||
switch a.Kind {
|
||||
|
@ -69,7 +69,7 @@ func (c *Call) validate(ctx *validCtx) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
switch arg.Type.(type) {
|
||||
switch typ1 := arg.Type.(type) {
|
||||
case *sys.ResourceType:
|
||||
switch arg.Kind {
|
||||
case ArgResult:
|
||||
@ -93,6 +93,10 @@ func (c *Call) validate(ctx *validCtx) error {
|
||||
default:
|
||||
return fmt.Errorf("syscall %v: union arg '%v' has bad kind %v", c.Meta.Name, typ.Name(), arg.Kind)
|
||||
}
|
||||
case *sys.ProcType:
|
||||
if arg.Val >= uintptr(typ1.ValuesPerProc) {
|
||||
return fmt.Errorf("syscall %v: per proc arg '%v' has bad value '%v'", c.Meta.Name, typ.Name(), arg.Val)
|
||||
}
|
||||
}
|
||||
switch arg.Kind {
|
||||
case ArgConst:
|
||||
|
@ -23,7 +23,7 @@ Pseudo-formal grammar of syscall description:
|
||||
type = typename [ "[" type-options "]" ]
|
||||
typename = "const" | "intN" | "intptr" | "flags" | "array" | "ptr" |
|
||||
"buffer" | "string" | "strconst" | "filename" |
|
||||
"len" | "bytesize" | "vma"
|
||||
"len" | "bytesize" | "vma" | "proc"
|
||||
type-options = [type-opt ["," type-opt]]
|
||||
```
|
||||
common type-options include:
|
||||
@ -55,6 +55,8 @@ rest of the type-options are type-specific:
|
||||
"bytesize": similar to "len", but always denotes the size in bytes, type-options:
|
||||
argname of the object
|
||||
"vma": a pointer to a set of pages (used as input for mmap/munmap/mremap/madvise)
|
||||
"proc": per process int (see description below), type-options:
|
||||
underlying type, value range start, how many values per process
|
||||
```
|
||||
flags/len/flags also have trailing underlying type type-option when used in structs/unions/pointers.
|
||||
|
||||
@ -108,6 +110,15 @@ accept(fd sock, ...) sock
|
||||
listen(fd sock, backlog int32)
|
||||
```
|
||||
|
||||
### Proc
|
||||
|
||||
The `proc` type can be used to denote per process integers.
|
||||
The idea is to have a separate range of values for each executor, so they don't interfere.
|
||||
|
||||
The simplest example is a port number.
|
||||
The `proc[int16be, 20000, 4]` type means that we want to generate an `int16be` integer starting from `20000` and assign no more than `4` integers for each process.
|
||||
As a result the executor number `n` will get values in the `[20000 + n * 4, 20000 + (n + 1) * 4)` range.
|
||||
|
||||
### Misc
|
||||
|
||||
Description files also contain `include` directives that refer to Linux kernel header files
|
||||
|
19
sys/decl.go
19
sys/decl.go
@ -207,7 +207,6 @@ const (
|
||||
IntPlain IntKind = iota
|
||||
IntSignalno
|
||||
IntInaddr
|
||||
IntInport
|
||||
IntFileoff // offset within a file
|
||||
IntRange
|
||||
)
|
||||
@ -229,6 +228,22 @@ func (t *IntType) Align() uintptr {
|
||||
return t.Size()
|
||||
}
|
||||
|
||||
type ProcType struct {
|
||||
TypeCommon
|
||||
TypeSize uintptr
|
||||
BigEndian bool
|
||||
ValuesStart int64
|
||||
ValuesPerProc uint64
|
||||
}
|
||||
|
||||
func (t *ProcType) Size() uintptr {
|
||||
return t.TypeSize
|
||||
}
|
||||
|
||||
func (t *ProcType) Align() uintptr {
|
||||
return t.Size()
|
||||
}
|
||||
|
||||
type ArrayKind int
|
||||
|
||||
const (
|
||||
@ -478,7 +493,7 @@ func ForeachType(meta *Call, f func(Type)) {
|
||||
rec(opt)
|
||||
}
|
||||
case *ResourceType, *BufferType, *VmaType, *LenType,
|
||||
*FlagsType, *ConstType, *IntType:
|
||||
*FlagsType, *ConstType, *IntType, *ProcType:
|
||||
default:
|
||||
panic("unknown type")
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ sockopt_opt_ipv6_mreq = IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_JOIN_ANY
|
||||
|
||||
sockaddr_in {
|
||||
family const[AF_INET, int16]
|
||||
port in_port
|
||||
port proc[int16be, 20000, 4]
|
||||
addr in_addr
|
||||
}
|
||||
|
||||
@ -130,7 +130,7 @@ sockaddr_storage_in {
|
||||
|
||||
sockaddr_in6 {
|
||||
family const[AF_INET6, int16]
|
||||
port in_port
|
||||
port proc[int16be, 20000, 4]
|
||||
flow int32
|
||||
addr in6_addr
|
||||
scope int32
|
||||
|
@ -975,9 +975,9 @@ xfrm_user_tmpl {
|
||||
xfrm_selector {
|
||||
daddr in_addr_any
|
||||
saddr in_addr_any
|
||||
dport in_port
|
||||
dport proc[int16be, 20000, 4]
|
||||
dmask int16
|
||||
sport in_port
|
||||
sport proc[int16be, 20000, 4]
|
||||
smask int16
|
||||
fam int16
|
||||
len_d int8
|
||||
|
@ -532,6 +532,44 @@ func generateArg(
|
||||
skipSyscall(fmt.Sprintf("missing const %v", a[0]))
|
||||
}
|
||||
fmt.Fprintf(out, "&ConstType{%v, TypeSize: %v, BigEndian: %v, Val: uintptr(%v)}", common(), size, bigEndian, val)
|
||||
case "proc":
|
||||
canBeArg = true
|
||||
size := uint64(ptrSize)
|
||||
bigEndian := false
|
||||
var valuesStart string
|
||||
var valuesPerProc string
|
||||
if isField {
|
||||
if want := 3; len(a) != want {
|
||||
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
|
||||
}
|
||||
size, bigEndian = decodeIntType(a[0])
|
||||
valuesStart = a[1]
|
||||
valuesPerProc = a[2]
|
||||
} else {
|
||||
if want := 2; len(a) != want {
|
||||
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
|
||||
}
|
||||
valuesStart = a[0]
|
||||
valuesPerProc = a[1]
|
||||
}
|
||||
valuesStartInt, err := strconv.ParseInt(valuesStart, 10, 64)
|
||||
if err != nil {
|
||||
failf("couldn't parse '%v' as int64", valuesStart)
|
||||
}
|
||||
valuesPerProcInt, err := strconv.ParseInt(valuesPerProc, 10, 64)
|
||||
if err != nil {
|
||||
failf("couldn't parse '%v' as int64", valuesPerProc)
|
||||
}
|
||||
if valuesPerProcInt < 1 {
|
||||
failf("values per proc '%v' should be >= 1", valuesPerProcInt)
|
||||
}
|
||||
if valuesStartInt >= (1 << (size * 8)) {
|
||||
failf("values starting from '%v' overflow desired type of size '%v'", valuesStartInt, size)
|
||||
}
|
||||
if valuesStartInt + 32 * valuesPerProcInt >= (1 << (size * 8)) {
|
||||
failf("not enough values starting from '%v' with step '%v' and type size '%v' for 32 procs", valuesStartInt, valuesPerProcInt, size)
|
||||
}
|
||||
fmt.Fprintf(out, "&ProcType{%v, TypeSize: %v, BigEndian: %v, ValuesStart: %v, ValuesPerProc: %v}", common(), size, bigEndian, valuesStartInt, valuesPerProcInt)
|
||||
case "int8", "int16", "int32", "int64", "intptr", "int16be", "int32be", "int64be", "intptrbe":
|
||||
canBeArg = true
|
||||
size, bigEndian := decodeIntType(typ)
|
||||
@ -555,11 +593,6 @@ func generateArg(
|
||||
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
|
||||
}
|
||||
fmt.Fprintf(out, "&IntType{%v, TypeSize: 4, Kind: IntInaddr}", common())
|
||||
case "in_port":
|
||||
if want := 0; len(a) != want {
|
||||
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
|
||||
}
|
||||
fmt.Fprintf(out, "&IntType{%v, TypeSize: 2, Kind: IntInport}", common())
|
||||
case "filename":
|
||||
canBeArg = true
|
||||
if want := 0; len(a) != want {
|
||||
|
@ -151,7 +151,7 @@ func main() {
|
||||
needPoll <- struct{}{}
|
||||
envs := make([]*ipc.Env, *flagProcs)
|
||||
for pid := 0; pid < *flagProcs; pid++ {
|
||||
env, err := ipc.MakeEnv(*flagExecutor, timeout, flags)
|
||||
env, err := ipc.MakeEnv(*flagExecutor, timeout, flags, pid)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func main() {
|
||||
pid := p
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
env, err := ipc.MakeEnv(*flagExecutor, timeout, flags)
|
||||
env, err := ipc.MakeEnv(*flagExecutor, timeout, flags, pid)
|
||||
if err != nil {
|
||||
Fatalf("failed to create ipc env: %v", err)
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func main() {
|
||||
for pid := 0; pid < *flagProcs; pid++ {
|
||||
pid := pid
|
||||
go func() {
|
||||
env, err := ipc.MakeEnv(*flagExecutor, timeout, flags)
|
||||
env, err := ipc.MakeEnv(*flagExecutor, timeout, flags, pid)
|
||||
if err != nil {
|
||||
Fatalf("failed to create execution environment: %v", err)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user