aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/host/host_linux.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-03-05 12:07:59 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-03-05 12:10:27 +0100
commit42467f5b7bf4eef20f78f796fc6eb10401784d86 (patch)
tree6dd3caddad413b777f407abdcd1969b15cb40a84 /pkg/host/host_linux.go
parente91c118db99874bef7e2cd657505aa4bafbbb6fa (diff)
sys/linux: add syz_init_net_socket syscall
The new pseudo syscall allows opening sockets that can only be created in init net namespace (BLUETOOTH, NFC, LLC). Use it to open these sockets. Unfortunately this only works with sandbox none at the moment. The problem is that setns of a network namespace requires CAP_SYS_ADMIN in the target namespace, and we've lost all privs in the init namespace during creation of a user namespace.
Diffstat (limited to 'pkg/host/host_linux.go')
-rw-r--r--pkg/host/host_linux.go47
1 files changed, 23 insertions, 24 deletions
diff --git a/pkg/host/host_linux.go b/pkg/host/host_linux.go
index fd3dc5bb8..57ce3e79e 100644
--- a/pkg/host/host_linux.go
+++ b/pkg/host/host_linux.go
@@ -17,7 +17,7 @@ import (
)
// DetectSupportedSyscalls returns list on supported syscalls on host.
-func DetectSupportedSyscalls(target *prog.Target) (map[*prog.Syscall]bool, error) {
+func DetectSupportedSyscalls(target *prog.Target, sandbox string) (map[*prog.Syscall]bool, error) {
// There are 3 possible strategies:
// 1. Executes all syscalls with presumably invalid arguments and check for ENOprog.
// But not all syscalls are safe to execute. For example, pause will hang,
@@ -31,23 +31,20 @@ func DetectSupportedSyscalls(target *prog.Target) (map[*prog.Syscall]bool, error
kallsyms, _ := ioutil.ReadFile("/proc/kallsyms")
supported := make(map[*prog.Syscall]bool)
for _, c := range target.Syscalls {
- if isSupported(kallsyms, c) {
+ if isSupported(sandbox, kallsyms, c) {
supported[c] = true
}
}
return supported, nil
}
-func isSupported(kallsyms []byte, c *prog.Syscall) bool {
+func isSupported(sandbox string, kallsyms []byte, c *prog.Syscall) bool {
if strings.HasPrefix(c.CallName, "syz_") {
- return isSupportedSyzkall(c)
+ return isSupportedSyzkall(sandbox, c)
}
if strings.HasPrefix(c.Name, "socket$") {
return isSupportedSocket(c)
}
- if strings.HasPrefix(c.Name, "open$") {
- return isSupportedOpen(c)
- }
if strings.HasPrefix(c.Name, "openat$") {
return isSupportedOpenAt(c)
}
@@ -69,7 +66,7 @@ var kallsymsMap = map[string]string{
"umount2": "umount",
}
-func isSupportedSyzkall(c *prog.Syscall) bool {
+func isSupportedSyzkall(sandbox string, c *prog.Syscall) bool {
switch c.CallName {
case "syz_open_dev":
if _, ok := c.Args[0].(*prog.ConstType); ok {
@@ -81,7 +78,7 @@ func isSupportedSyzkall(c *prog.Syscall) bool {
if !ok {
panic("first open arg is not a pointer to string const")
}
- if syscall.Getuid() != 0 {
+ if syscall.Getuid() != 0 || sandbox == "setuid" {
return false
}
var check func(dev string) bool
@@ -102,15 +99,21 @@ func isSupportedSyzkall(c *prog.Syscall) bool {
case "syz_open_pts":
return true
case "syz_fuse_mount":
+ if syscall.Getuid() != 0 || sandbox == "setuid" {
+ return false
+ }
return osutil.IsExist("/dev/fuse")
case "syz_fuseblk_mount":
- return osutil.IsExist("/dev/fuse") && syscall.Getuid() == 0
+ if syscall.Getuid() != 0 || sandbox == "setuid" {
+ return false
+ }
+ return osutil.IsExist("/dev/fuse")
case "syz_emit_ethernet", "syz_extract_tcp_res":
fd, err := syscall.Open("/dev/net/tun", syscall.O_RDWR, 0)
if err == nil {
syscall.Close(fd)
}
- return err == nil && syscall.Getuid() == 0
+ return err == nil
case "syz_kvm_setup_cpu":
switch c.Name {
case "syz_kvm_setup_cpu$x86":
@@ -118,6 +121,15 @@ func isSupportedSyzkall(c *prog.Syscall) bool {
case "syz_kvm_setup_cpu$arm64":
return runtime.GOARCH == "arm64"
}
+ case "syz_init_net_socket":
+ // Unfortunately this only works with sandbox none at the moment.
+ // The problem is that setns of a network namespace requires CAP_SYS_ADMIN
+ // in the target namespace, and we've lost all privs in the init namespace
+ // during creation of a user namespace.
+ if syscall.Getuid() != 0 || sandbox != "none" {
+ return false
+ }
+ return isSupportedSocket(c)
}
panic("unknown syzkall: " + c.Name)
}
@@ -125,7 +137,6 @@ func isSupportedSyzkall(c *prog.Syscall) bool {
func isSupportedSocket(c *prog.Syscall) bool {
af, ok := c.Args[0].(*prog.ConstType)
if !ok {
- println(c.Name)
panic("socket family is not const")
}
fd, err := syscall.Socket(int(af.Val), 0, 0)
@@ -135,18 +146,6 @@ func isSupportedSocket(c *prog.Syscall) bool {
return err != syscall.ENOSYS && err != syscall.EAFNOSUPPORT
}
-func isSupportedOpen(c *prog.Syscall) bool {
- fname, ok := extractStringConst(c.Args[0])
- if !ok {
- return true
- }
- fd, err := syscall.Open(fname, syscall.O_RDONLY, 0)
- if fd != -1 {
- syscall.Close(fd)
- }
- return err == nil
-}
-
func isSupportedOpenAt(c *prog.Syscall) bool {
fname, ok := extractStringConst(c.Args[1])
if !ok {