aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/instance
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2026-01-27 14:29:05 +0000
committerAleksandr Nogikh <nogikh@google.com>2026-02-17 14:55:28 +0000
commit5c431cdadf7d8c81afa46915b85f6a63aaff9871 (patch)
tree94bee31158b5a98df57e406d76053dba54510596 /pkg/instance
parent72e0f1b67bdd3f89cf51e89a3c17dd4a7cb575f1 (diff)
pkg/instance: extract crash dumps
If the crash dumps are enabled, collect one crash dump per each crash when fuzzing locally. Optionally also collect crash dumps in pkg/instance's Test(). Inspired by Chenxi Huang's downstream changes to syzkaller.
Diffstat (limited to 'pkg/instance')
-rw-r--r--pkg/instance/dump.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/pkg/instance/dump.go b/pkg/instance/dump.go
new file mode 100644
index 000000000..1544f3f93
--- /dev/null
+++ b/pkg/instance/dump.go
@@ -0,0 +1,86 @@
+// Copyright 2026 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 instance
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/google/syzkaller/pkg/log"
+ "github.com/google/syzkaller/sys/targets"
+ "github.com/google/syzkaller/vm"
+ "github.com/google/syzkaller/vm/vmimpl"
+)
+
+func ExtractMemoryDump(inst *vm.Instance, target *targets.Target, path string) error {
+ // TODO: if the instance has not yet panicked, we could cause the panic
+ // by writing to /proc/sys/kernel/sysrq. But the problem is that we don't
+ // want to enable CONFIG_MAGIC_SYSRQ during fuzzing.
+ const (
+ // To extract the crash dump, we need to SSH into the crash kernel.
+ // As it takes time for the new kernel to fully load and we don't
+ // know it exactly, we do several attempts.
+ maxRetries = 100
+ retrySleep = 3 * time.Second
+ // Using more restrictive masks somhow causes the crash utility to fail.
+ cmd = "/usr/sbin/makedumpfile -F -c -d 0 /proc/vmcore"
+ )
+ if target.OS != targets.Linux {
+ return fmt.Errorf("memory dump collection is only supported on linux")
+ }
+ var lastErr error
+ for i := 0; i < maxRetries; i++ {
+ err := extractKdumpInner(inst, path, cmd)
+ if err == nil {
+ return nil
+ }
+ lastErr = err
+ log.Logf(2, "[instance #%d] failed to extract memory dump: %v",
+ inst.Index(), err)
+ time.Sleep(retrySleep)
+ }
+ return fmt.Errorf("failed to extract memory dump after %v attempts: %w", maxRetries, lastErr)
+}
+
+func extractKdumpInner(inst *vm.Instance, path, cmd string) error {
+ // We need a long timeout for dump extraction, it can be hundreds of megabytes.
+ // 1 hour timeout should be enough for the typical scenarios.
+ ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
+ defer cancel()
+
+ outc, errc, err := inst.RunStream(ctx, cmd)
+ if err != nil {
+ return fmt.Errorf("failed to start command: %w", err)
+ }
+
+ f, err := os.Create(path)
+ if err != nil {
+ return fmt.Errorf("failed to create dump file: %w", err)
+ }
+ defer f.Close()
+
+ for {
+ select {
+ case chunk, ok := <-outc:
+ if !ok {
+ outc = nil
+ continue
+ }
+ if chunk.Type != vmimpl.OutputStdout {
+ // Filter out console and stderr.
+ continue
+ }
+ if _, err := f.Write(chunk.Data); err != nil {
+ return fmt.Errorf("failed to write to dump file: %w", err)
+ }
+ case err := <-errc:
+ return err
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+ }
+ return nil
+}