From 5c431cdadf7d8c81afa46915b85f6a63aaff9871 Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Tue, 27 Jan 2026 14:29:05 +0000 Subject: 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. --- pkg/instance/dump.go | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 pkg/instance/dump.go (limited to 'pkg/instance') 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 +} -- cgit mrf-deployment