sys: dedup sanitization of common unix syscalls

Update #538
This commit is contained in:
Dmitry Vyukov 2018-05-07 14:42:55 +02:00
parent 068da17e1f
commit f914e0a305
4 changed files with 79 additions and 110 deletions

View File

@ -6,7 +6,7 @@
"minconstlength": 7,
"linelength": 120,
"cyclo": 50,
"duplthreshold": 83,
"duplthreshold": 80,
"skip": [
"pkg/kd",
"sys/akaros/gen",
@ -34,7 +34,7 @@
],
"exclude": [
"don't use underscores in Go names",
"sys/(akaros|freebsd|fuchsia|linux|netbsd|test|windows)/init.* don't use ALL_CAPS in Go names",
"(sys/(akaros|freebsd|fuchsia|linux|netbsd|test|windows)/init.*|sys/targets/common.go).* don't use ALL_CAPS in Go names",
"exported .* should have comment",
"comment on .* should be of the form",
"(pkg/ifuzz/insns.go|pkg/csource/.*_common.go|pkg/csource/gen.go|pkg/report/linux.go|pkg/kernel/generated.go).* line is [0-9]+ characters"

View File

@ -15,62 +15,13 @@ func init() {
func initTarget(target *prog.Target) {
arch := &arch{
MAP_FIXED: target.ConstMap["MAP_FIXED"],
S_IFREG: target.ConstMap["S_IFREG"],
S_IFCHR: target.ConstMap["S_IFCHR"],
S_IFBLK: target.ConstMap["S_IFBLK"],
S_IFIFO: target.ConstMap["S_IFIFO"],
S_IFSOCK: target.ConstMap["S_IFSOCK"],
unix: targets.MakeUnixSanitizer(target),
}
target.MakeMmap = targets.MakePosixMmap(target)
target.SanitizeCall = arch.sanitizeCall
target.SanitizeCall = arch.unix.SanitizeCall
}
type arch struct {
MAP_FIXED uint64
S_IFREG uint64
S_IFCHR uint64
S_IFBLK uint64
S_IFIFO uint64
S_IFSOCK uint64
}
func (arch *arch) sanitizeCall(c *prog.Call) {
switch c.Meta.CallName {
case "mmap":
// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
c.Args[3].(*prog.ConstArg).Val |= arch.MAP_FIXED
case "mknod", "mknodat":
pos := 1
if c.Meta.CallName == "mknodat" {
pos = 2
}
mode := c.Args[pos].(*prog.ConstArg)
dev := c.Args[pos+1].(*prog.ConstArg)
// Char and block devices read/write io ports, kernel memory and do other nasty things.
// TODO: not required if executor drops privileges.
switch mode.Val & (arch.S_IFREG | arch.S_IFCHR | arch.S_IFBLK | arch.S_IFIFO | arch.S_IFSOCK) {
case arch.S_IFREG, arch.S_IFIFO, arch.S_IFSOCK:
case arch.S_IFBLK:
// TODO(dvyukov): mknod dev argument is uint32,
// but prog arguments contain not-truncated uint64 values,
// so we can mistakenly assume that this is not loop, when it actually is.
// This is not very harmful, but need to verify other arguments in this function.
if dev.Val>>8 == 7 {
break // loop
}
mode.Val &^= arch.S_IFBLK
mode.Val |= arch.S_IFREG
case arch.S_IFCHR:
mode.Val &^= arch.S_IFCHR
mode.Val |= arch.S_IFREG
}
case "exit":
code := c.Args[0].(*prog.ConstArg)
// These codes are reserved by executor.
if code.Val%128 == 67 || code.Val%128 == 68 {
code.Val = 1
}
}
unix *targets.UnixSanitizer
}

View File

@ -21,15 +21,8 @@ func init() {
func initTarget(target *prog.Target) {
arch := &arch{
unix: targets.MakeUnixSanitizer(target),
clockGettimeSyscall: target.SyscallMap["clock_gettime"],
MAP_FIXED: target.ConstMap["MAP_FIXED"],
MREMAP_MAYMOVE: target.ConstMap["MREMAP_MAYMOVE"],
MREMAP_FIXED: target.ConstMap["MREMAP_FIXED"],
S_IFREG: target.ConstMap["S_IFREG"],
S_IFCHR: target.ConstMap["S_IFCHR"],
S_IFBLK: target.ConstMap["S_IFBLK"],
S_IFIFO: target.ConstMap["S_IFIFO"],
S_IFSOCK: target.ConstMap["S_IFSOCK"],
SYSLOG_ACTION_CONSOLE_OFF: target.ConstMap["SYSLOG_ACTION_CONSOLE_OFF"],
SYSLOG_ACTION_CONSOLE_ON: target.ConstMap["SYSLOG_ACTION_CONSOLE_ON"],
SYSLOG_ACTION_SIZE_UNREAD: target.ConstMap["SYSLOG_ACTION_SIZE_UNREAD"],
@ -86,16 +79,10 @@ var (
)
type arch struct {
unix *targets.UnixSanitizer
clockGettimeSyscall *prog.Syscall
MAP_FIXED uint64
MREMAP_MAYMOVE uint64
MREMAP_FIXED uint64
S_IFREG uint64
S_IFCHR uint64
S_IFBLK uint64
S_IFIFO uint64
S_IFSOCK uint64
SYSLOG_ACTION_CONSOLE_OFF uint64
SYSLOG_ACTION_CONSOLE_ON uint64
SYSLOG_ACTION_SIZE_UNREAD uint64
@ -111,41 +98,8 @@ type arch struct {
}
func (arch *arch) sanitizeCall(c *prog.Call) {
arch.unix.SanitizeCall(c)
switch c.Meta.CallName {
case "mmap":
// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
c.Args[3].(*prog.ConstArg).Val |= arch.MAP_FIXED
case "mremap":
// Add MREMAP_FIXED flag, otherwise it produces non-deterministic results.
flags := c.Args[3].(*prog.ConstArg)
if flags.Val&arch.MREMAP_MAYMOVE != 0 {
flags.Val |= arch.MREMAP_FIXED
}
case "mknod", "mknodat":
pos := 1
if c.Meta.CallName == "mknodat" {
pos = 2
}
if _, ok := c.Args[pos+1].Type().(*prog.ProcType); ok {
return
}
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.
switch mode.Val & (arch.S_IFREG | arch.S_IFCHR | arch.S_IFBLK | arch.S_IFIFO | arch.S_IFSOCK) {
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:
mode.Val &^= arch.S_IFCHR
mode.Val |= arch.S_IFREG
}
case "syslog":
cmd := c.Args[0].(*prog.ConstArg)
cmd.Val = uint64(uint32(cmd.Val))
@ -168,12 +122,6 @@ func (arch *arch) sanitizeCall(c *prog.Call) {
if req.Val == arch.PTRACE_TRACEME {
req.Val = ^uint64(0)
}
case "exit", "exit_group":
code := c.Args[0].(*prog.ConstArg)
// These codes are reserved by executor.
if code.Val%128 == 67 || code.Val%128 == 68 {
code.Val = 1
}
case "arch_prctl":
// fs holds address of tls, if a program messes it at least signal
// handling will break. This also allows a program to do writes

View File

@ -42,3 +42,73 @@ func MakeSyzMmap(target *prog.Target) func(addr, size uint64) *prog.Call {
}
}
}
type UnixSanitizer struct {
MAP_FIXED uint64
MREMAP_MAYMOVE uint64
MREMAP_FIXED uint64
S_IFREG uint64
S_IFCHR uint64
S_IFBLK uint64
S_IFIFO uint64
S_IFSOCK uint64
}
func MakeUnixSanitizer(target *prog.Target) *UnixSanitizer {
return &UnixSanitizer{
MAP_FIXED: target.ConstMap["MAP_FIXED"],
MREMAP_MAYMOVE: target.ConstMap["MREMAP_MAYMOVE"],
MREMAP_FIXED: target.ConstMap["MREMAP_FIXED"],
S_IFREG: target.ConstMap["S_IFREG"],
S_IFCHR: target.ConstMap["S_IFCHR"],
S_IFBLK: target.ConstMap["S_IFBLK"],
S_IFIFO: target.ConstMap["S_IFIFO"],
S_IFSOCK: target.ConstMap["S_IFSOCK"],
}
}
func (arch *UnixSanitizer) SanitizeCall(c *prog.Call) {
switch c.Meta.CallName {
case "mmap":
// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
c.Args[3].(*prog.ConstArg).Val |= arch.MAP_FIXED
case "mremap":
// Add MREMAP_FIXED flag, otherwise it produces non-deterministic results.
flags := c.Args[3].(*prog.ConstArg)
if flags.Val&arch.MREMAP_MAYMOVE != 0 {
flags.Val |= arch.MREMAP_FIXED
}
case "mknod", "mknodat":
pos := 1
if c.Meta.CallName == "mknodat" {
pos = 2
}
if _, ok := c.Args[pos+1].Type().(*prog.ProcType); ok {
return
}
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:
mode.Val &^= arch.S_IFCHR
mode.Val |= arch.S_IFREG
}
case "exit", "exit_group":
code := c.Args[0].(*prog.ConstArg)
// These codes are reserved by executor.
if code.Val%128 == 67 || code.Val%128 == 68 {
code.Val = 1
}
}
}