diff options
Diffstat (limited to 'pkg/host')
| -rw-r--r-- | pkg/host/host.go | 22 | ||||
| -rw-r--r-- | pkg/host/host_linux.go | 38 |
2 files changed, 22 insertions, 38 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() |
