aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-11-19 10:53:39 +0100
committerDmitry Vyukov <dvyukov@google.com>2020-11-21 09:22:22 +0100
commitc7ec2d19f82830161738378f96761b57328eed7a (patch)
tree86224fb35bf138ed6c9cd8ad3fbf47c080a8c93a
parent22238b0b79fc80d9a0218f8bf9ecf3e91401bd12 (diff)
vm/qemu, vm/gce: dump LOCKDEP state in Diagnose
For context see the discussion at: https://groups.google.com/g/syzkaller/c/ruwaYUvwHTw/m/E9Cg9OfvAgAJ
-rw-r--r--vm/gce/gce.go30
-rw-r--r--vm/qemu/qemu.go14
-rw-r--r--vm/vmimpl/linux.go26
3 files changed, 60 insertions, 10 deletions
diff --git a/vm/gce/gce.go b/vm/gce/gce.go
index b5565aff0..c4cd9f184 100644
--- a/vm/gce/gce.go
+++ b/vm/gce/gce.go
@@ -20,6 +20,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "strings"
"time"
"github.com/google/syzkaller/pkg/config"
@@ -266,13 +267,7 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
sshRpipe.Close()
return nil, nil, err
}
- if inst.env.OS == targets.Linux {
- if inst.sshUser != "root" {
- command = fmt.Sprintf("sudo bash -c '%v'", command)
- }
- }
- args := append(vmimpl.SSHArgs(inst.debug, inst.sshKey, 22), inst.sshUser+"@"+inst.ip, command)
- ssh := osutil.Command("ssh", args...)
+ ssh := osutil.Command("ssh", inst.sshArgs(command)...)
ssh.Stdout = sshWpipe
ssh.Stderr = sshWpipe
if err := ssh.Start(); err != nil {
@@ -371,15 +366,30 @@ func waitForConsoleConnect(merger *vmimpl.OutputMerger) error {
}
func (inst *instance) Diagnose(rep *report.Report) ([]byte, bool) {
- if inst.env.OS == targets.FreeBSD {
+ switch inst.env.OS {
+ case targets.Linux:
+ output, wait, _ := vmimpl.DiagnoseLinux(rep, inst.ssh)
+ return output, wait
+ case targets.FreeBSD:
return vmimpl.DiagnoseFreeBSD(inst.consolew)
- }
- if inst.env.OS == targets.OpenBSD {
+ case targets.OpenBSD:
return vmimpl.DiagnoseOpenBSD(inst.consolew)
}
return nil, false
}
+func (inst *instance) ssh(args ...string) ([]byte, error) {
+ return osutil.RunCmd(time.Minute, "", "ssh", inst.sshArgs(args...)...)
+}
+
+func (inst *instance) sshArgs(args ...string) []string {
+ sshArgs := append(vmimpl.SSHArgs(inst.debug, inst.sshKey, 22), inst.sshUser+"@"+inst.ip)
+ if inst.env.OS == targets.Linux && inst.sshUser != "root" {
+ args = []string{"sudo", "bash", "-c", "'" + strings.Join(args, " ") + "'"}
+ }
+ return append(sshArgs, args...)
+}
+
func (pool *Pool) getSerialPortOutput(name, gceKey string) ([]byte, error) {
conRpipe, conWpipe, err := osutil.LongPipe()
if err != nil {
diff --git a/vm/qemu/qemu.go b/vm/qemu/qemu.go
index d0689fa1d..eaa82cbb2 100644
--- a/vm/qemu/qemu.go
+++ b/vm/qemu/qemu.go
@@ -621,6 +621,11 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
}
func (inst *instance) Diagnose(rep *report.Report) ([]byte, bool) {
+ if inst.target.OS == targets.Linux {
+ if output, wait, handled := vmimpl.DiagnoseLinux(rep, inst.ssh); handled {
+ return output, wait
+ }
+ }
// TODO: we don't need registers on all reports. Probably only relevant for "crashes"
// (NULL derefs, paging faults, etc), but is not useful for WARNING/BUG/HANG (?).
ret := []byte(fmt.Sprintf("%s Registers:\n", time.Now().Format("15:04:05 ")))
@@ -637,6 +642,15 @@ func (inst *instance) Diagnose(rep *report.Report) ([]byte, bool) {
return ret, false
}
+func (inst *instance) ssh(args ...string) ([]byte, error) {
+ return osutil.RunCmd(time.Minute, "", "ssh", inst.sshArgs(args...)...)
+}
+
+func (inst *instance) sshArgs(args ...string) []string {
+ sshArgs := append(vmimpl.SSHArgs(inst.debug, inst.sshkey, inst.port), inst.sshuser+"@localhost")
+ return append(sshArgs, args...)
+}
+
// nolint: lll
const initScript = `#! /bin/bash
set -eux
diff --git a/vm/vmimpl/linux.go b/vm/vmimpl/linux.go
new file mode 100644
index 000000000..0406035f6
--- /dev/null
+++ b/vm/vmimpl/linux.go
@@ -0,0 +1,26 @@
+// Copyright 2020 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 vmimpl
+
+import (
+ "regexp"
+ "strings"
+
+ "github.com/google/syzkaller/pkg/report"
+)
+
+// DiagnoseLinux diagnoses some Linux kernel bugs over the provided ssh callback.
+func DiagnoseLinux(rep *report.Report, ssh func(args ...string) ([]byte, error)) (output []byte, wait, handled bool) {
+ if !strings.Contains(rep.Title, "MAX_LOCKDEP") {
+ return nil, false, false
+ }
+ // Dump /proc/lockdep* files on BUG: MAX_LOCKDEP_{KEYS,ENTRIES,CHAINS,CHAIN_HLOCKS} too low!
+ output, err := ssh("cat", "/proc/lockdep_stats", "/proc/lockdep", "/proc/lockdep_chains")
+ if err != nil {
+ output = append(output, err.Error()...)
+ }
+ // Remove mangled pointer values, they take lots of space but don't add any value.
+ output = regexp.MustCompile(` *\[?[0-9a-f]{8,}\]?\s*`).ReplaceAll(output, nil)
+ return output, false, true
+}