aboutsummaryrefslogtreecommitdiffstats
path: root/sys/targets/common.go
blob: b6827e76eee6fd98c41d592d65630a1466fdf9c2 (plain)
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2018 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 targets

import (
	"github.com/google/syzkaller/prog"
)

// MakePosixMmap creates a "normal" posix mmap call that maps the target data range.
// If exec is set, the mapping is mapped as PROT_EXEC.
// If contain is set, the mapping is surrounded by PROT_NONE pages.
// These flags should be in sync with what executor.
func MakePosixMmap(target *prog.Target, exec, contain bool) func() []*prog.Call {
	meta := target.SyscallMap["mmap"]
	protRW := target.GetConst("PROT_READ") | target.GetConst("PROT_WRITE")
	if exec {
		protRW |= target.GetConst("PROT_EXEC")
	}
	flags := target.GetConst("MAP_ANONYMOUS") | target.GetConst("MAP_PRIVATE") | target.GetConst("MAP_FIXED")
	size := target.NumPages * target.PageSize
	const invalidFD = ^uint64(0)
	makeMmap := func(addr, size, prot uint64) *prog.Call {
		call := prog.MakeCall(meta, []prog.Arg{
			prog.MakeVmaPointerArg(meta.Args[0].Type, prog.DirIn, addr, size),
			prog.MakeConstArg(meta.Args[1].Type, prog.DirIn, size),
			prog.MakeConstArg(meta.Args[2].Type, prog.DirIn, prot),
			prog.MakeConstArg(meta.Args[3].Type, prog.DirIn, flags),
			prog.MakeResultArg(meta.Args[4].Type, prog.DirIn, nil, invalidFD),
		})
		i := len(call.Args)
		// Some targets have a padding argument between fd and offset.
		if len(meta.Args) > 6 {
			call.Args = append(call.Args, prog.MakeConstArg(meta.Args[i].Type, prog.DirIn, 0))
			i++
		}
		call.Args = append(call.Args, prog.MakeConstArg(meta.Args[i].Type, prog.DirIn, 0))
		return call
	}
	return func() []*prog.Call {
		if contain {
			return []*prog.Call{
				makeMmap(^target.PageSize+1, target.PageSize, 0),
				makeMmap(0, size, protRW),
				makeMmap(size, target.PageSize, 0),
			}
		}
		return []*prog.Call{makeMmap(0, size, protRW)}
	}
}

func MakeSyzMmap(target *prog.Target) func() []*prog.Call {
	meta := target.SyscallMap["syz_mmap"]
	size := target.NumPages * target.PageSize
	return func() []*prog.Call {
		return []*prog.Call{
			prog.MakeCall(meta, []prog.Arg{
				prog.MakeVmaPointerArg(meta.Args[0].Type, prog.DirIn, 0, size),
				prog.MakeConstArg(meta.Args[1].Type, prog.DirIn, size),
			}),
		}
	}
}

type UnixNeutralizer struct {
	MAP_FIXED uint64
	S_IFREG   uint64
	S_IFCHR   uint64
	S_IFBLK   uint64
	S_IFIFO   uint64
	S_IFSOCK  uint64
}

func MakeUnixNeutralizer(target *prog.Target) *UnixNeutralizer {
	return &UnixNeutralizer{
		MAP_FIXED: target.GetConst("MAP_FIXED"),
		S_IFREG:   target.GetConst("S_IFREG"),
		S_IFCHR:   target.GetConst("S_IFCHR"),
		S_IFBLK:   target.GetConst("S_IFBLK"),
		S_IFIFO:   target.GetConst("S_IFIFO"),
		S_IFSOCK:  target.GetConst("S_IFSOCK"),
	}
}

func (arch *UnixNeutralizer) Neutralize(c *prog.Call, fixStructure bool) error {
	switch c.Meta.CallName {
	case "mmap":
		if c.Meta.Name == "mmap$bifrost" {
			// Mali bifrost mmap doesn't support MAP_FIXED.
			return nil
		}
		// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
		c.Args[3].(*prog.ConstArg).Val |= arch.MAP_FIXED
	case "mknod", "mknodat", "compat_50_mknod":
		pos := 1
		if c.Meta.CallName == "mknodat" {
			pos = 2
		}
		switch c.Args[pos+1].Type().(type) {
		case *prog.ProcType, *prog.ResourceType:
			return nil
		}
		mode := c.Args[pos].(*prog.ConstArg)
		dev := c.Args[pos+1].(*prog.ConstArg)
		dev.Val = uint64(uint32(dev.Val))
		// Char and block devices read/write io ports, kernel memory and do other nasty things.
		// TODO: not required if executor drops privileges.
		mask := arch.S_IFREG | arch.S_IFCHR | arch.S_IFBLK | arch.S_IFIFO | arch.S_IFSOCK
		switch mode.Val & mask {
		case arch.S_IFREG, arch.S_IFIFO, arch.S_IFSOCK:
		case arch.S_IFBLK:
			if dev.Val>>8 == 7 {
				break // loop
			}
			mode.Val &^= arch.S_IFBLK
			mode.Val |= arch.S_IFREG
		case arch.S_IFCHR:
			if dev.Val == 0x103 {
				break // /dev/null
			}
			mode.Val &^= arch.S_IFCHR
			mode.Val |= arch.S_IFREG
		}
	case "exit", "exit_group":
		code := c.Args[0].(*prog.ConstArg)
		// This code is reserved by executor.
		if code.Val%128 == 67 {
			code.Val = 1
		}
	}
	return nil
}