aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/host/host.go22
-rw-r--r--pkg/host/host_linux.go38
-rw-r--r--pkg/ipc/ipcconfig/ipcconfig.go41
-rw-r--r--pkg/rpctype/rpctype.go11
-rw-r--r--pkg/runtest/run.go12
5 files changed, 63 insertions, 61 deletions
diff --git a/pkg/host/host.go b/pkg/host/host.go
index b23dd9ab2..36c42de65 100644
--- a/pkg/host/host.go
+++ b/pkg/host/host.go
@@ -65,7 +65,7 @@ type Features [numFeatures]Feature
var checkFeature [numFeatures]func() string
var setupFeature [numFeatures]func() error
-var callbFeature [numFeatures]func()
+var callbFeature [numFeatures]func(leakFrames [][]byte)
func unconditionallyEnabled() string { return "" }
@@ -104,11 +104,11 @@ func Check(target *prog.Target) (*Features, error) {
// Setup enables and does any one-time setup for the requested features on the host.
// Note: this can be called multiple times and must be idempotent.
-func Setup(target *prog.Target, features *Features) (func(), error) {
+func Setup(target *prog.Target, features *Features) (func(leakFrames [][]byte), error) {
if target.OS == "akaros" || target.OS == "test" {
return nil, nil
}
- var callback func()
+ var callback func([][]byte)
for n, setup := range setupFeature {
if setup == nil || !features[n].Enabled {
continue
@@ -117,15 +117,15 @@ func Setup(target *prog.Target, features *Features) (func(), error) {
return nil, err
}
cb := callbFeature[n]
- if cb != nil {
- prev := callback
- callback = func() {
- cb()
- if prev != nil {
- prev()
- }
+ if cb == nil {
+ continue
+ }
+ prev := callback
+ callback = func(leakFrames [][]byte) {
+ cb(leakFrames)
+ if prev != nil {
+ prev(leakFrames)
}
-
}
}
return callback, nil
diff --git a/pkg/host/host_linux.go b/pkg/host/host_linux.go
index 8214b35af..5c5db793b 100644
--- a/pkg/host/host_linux.go
+++ b/pkg/host/host_linux.go
@@ -469,7 +469,7 @@ func setupLeakChecking() error {
return nil
}
-func callbackLeakChecking() {
+func callbackLeakChecking(leakFrames [][]byte) {
start := time.Now()
fd, err := syscall.Open("/sys/kernel/debug/kmemleak", syscall.O_RDWR, 0)
if err != nil {
@@ -506,11 +506,15 @@ func callbackLeakChecking() {
if _, err := syscall.Write(fd, []byte("scan")); err != nil {
panic(err)
}
+ if _, err := syscall.Seek(fd, 0, 0); err != nil {
+ panic(err)
+ }
n, err := syscall.Read(fd, buf)
if err != nil {
panic(err)
}
nleaks := 0
+ nextLeak:
for buf = buf[:n]; len(buf) != 0; {
end := bytes.Index(buf[1:], []byte("unreferenced object"))
if end != -1 {
@@ -520,14 +524,18 @@ func callbackLeakChecking() {
}
report := buf[:end]
buf = buf[end:]
- if kmemleakIgnore(report) {
- continue
+ for _, frame := range leakFrames {
+ if bytes.Contains(report, frame) {
+ continue nextLeak
+ }
}
// BUG in output should be recognized by manager.
fmt.Printf("BUG: memory leak\n%s\n", report)
nleaks++
}
if nleaks != 0 {
+ // If we exit right away, dying executors will dump lots of garbage to console.
+ time.Sleep(time.Hour)
os.Exit(1)
}
}
@@ -536,30 +544,6 @@ func callbackLeakChecking() {
}
}
-func kmemleakIgnore(report []byte) bool {
- // kmemleak has a bunch of false positives (at least what looks like
- // false positives at first glance). So we are conservative with what we report.
- // First, we filter out any allocations that don't come from executor processes.
- // Second, we ignore a bunch of functions entirely.
- // Ideally, someone should debug/fix all these cases and remove ignores.
- if !bytes.Contains(report, []byte(`comm "syz-executor`)) {
- return true
- }
- for _, ignore := range []string{
- " copy_process",
- " do_execveat_common",
- " __ext4_",
- " get_empty_filp",
- " do_filp_open",
- " new_inode",
- } {
- if bytes.Contains(report, []byte(ignore)) {
- return true
- }
- }
- return false
-}
-
func checkSandboxNamespace() string {
if err := osutil.IsAccessible("/proc/self/ns/user"); err != nil {
return err.Error()
diff --git a/pkg/ipc/ipcconfig/ipcconfig.go b/pkg/ipc/ipcconfig/ipcconfig.go
index 021978274..b94579102 100644
--- a/pkg/ipc/ipcconfig/ipcconfig.go
+++ b/pkg/ipc/ipcconfig/ipcconfig.go
@@ -33,18 +33,11 @@ func Default(target *prog.Target) (*ipc.Config, *ipc.ExecOpts, error) {
if *flagDebug {
c.Flags |= ipc.FlagDebug
}
- switch *flagSandbox {
- case "none":
- case "setuid":
- c.Flags |= ipc.FlagSandboxSetuid
- case "namespace":
- c.Flags |= ipc.FlagSandboxNamespace
- case "android_untrusted_app":
- c.Flags |= ipc.FlagSandboxAndroidUntrustedApp
- default:
- return nil, nil, fmt.Errorf("flag sandbox must contain one of none/setuid/namespace/android_untrusted_app")
+ sandboxFlags, err := SandboxToFlags(*flagSandbox)
+ if err != nil {
+ return nil, nil, err
}
-
+ c.Flags |= sandboxFlags
sysTarget := targets.Get(target.OS, target.Arch)
if sysTarget.ExecutorUsesShmem {
c.Flags |= ipc.FlagUseShmem
@@ -65,3 +58,29 @@ func Default(target *prog.Target) (*ipc.Config, *ipc.ExecOpts, error) {
return c, opts, nil
}
+
+func SandboxToFlags(sandbox string) (ipc.EnvFlags, error) {
+ switch sandbox {
+ case "none":
+ return 0, nil
+ case "setuid":
+ return ipc.FlagSandboxSetuid, nil
+ case "namespace":
+ return ipc.FlagSandboxNamespace, nil
+ case "android_untrusted_app":
+ return ipc.FlagSandboxAndroidUntrustedApp, nil
+ default:
+ return 0, fmt.Errorf("sandbox must contain one of none/setuid/namespace/android_untrusted_app")
+ }
+}
+
+func FlagsToSandbox(flags ipc.EnvFlags) string {
+ if flags&ipc.FlagSandboxSetuid != 0 {
+ return "setuid"
+ } else if flags&ipc.FlagSandboxNamespace != 0 {
+ return "namespace"
+ } else if flags&ipc.FlagSandboxAndroidUntrustedApp != 0 {
+ return "android_untrusted_app"
+ }
+ return "none"
+}
diff --git a/pkg/rpctype/rpctype.go b/pkg/rpctype/rpctype.go
index eb2303950..68f85eedc 100644
--- a/pkg/rpctype/rpctype.go
+++ b/pkg/rpctype/rpctype.go
@@ -29,11 +29,12 @@ type ConnectArgs struct {
}
type ConnectRes struct {
- EnabledCalls []int
- GitRevision string
- TargetRevision string
- AllSandboxes bool
- CheckResult *CheckArgs
+ EnabledCalls []int
+ GitRevision string
+ TargetRevision string
+ AllSandboxes bool
+ CheckResult *CheckArgs
+ MemoryLeakFrames [][]byte
}
type CheckArgs struct {
diff --git a/pkg/runtest/run.go b/pkg/runtest/run.go
index 115f5ecb7..0ec0bb125 100644
--- a/pkg/runtest/run.go
+++ b/pkg/runtest/run.go
@@ -26,6 +26,7 @@ import (
"github.com/google/syzkaller/pkg/csource"
"github.com/google/syzkaller/pkg/host"
"github.com/google/syzkaller/pkg/ipc"
+ "github.com/google/syzkaller/pkg/ipc/ipcconfig"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys/targets"
@@ -307,14 +308,11 @@ func (ctx *Context) createSyzTest(p *prog.Prog, sandbox string, threaded, cov bo
if sysTarget.ExecutorUsesForkServer {
cfg.Flags |= ipc.FlagUseForkServer
}
- switch sandbox {
- case "namespace":
- cfg.Flags |= ipc.FlagSandboxNamespace
- case "setuid":
- cfg.Flags |= ipc.FlagSandboxSetuid
- case "android_untrusted_app":
- cfg.Flags |= ipc.FlagSandboxAndroidUntrustedApp
+ sandboxFlags, err := ipcconfig.SandboxToFlags(sandbox)
+ if err != nil {
+ return nil, err
}
+ cfg.Flags |= sandboxFlags
if threaded {
opts.Flags |= ipc.FlagThreaded | ipc.FlagCollide
}