Skip to content

Commit de24a22

Browse files
committed
pkg/aflow/action/crash/test: implement patch testing
1 parent b1fba58 commit de24a22

File tree

1 file changed

+89
-1
lines changed

1 file changed

+89
-1
lines changed

pkg/aflow/action/crash/test.go

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,19 @@ package crash
55

66
import (
77
"encoding/json"
8+
"errors"
9+
"fmt"
10+
"path"
11+
"path/filepath"
12+
"runtime"
13+
"time"
814

915
"github.com/google/syzkaller/pkg/aflow"
16+
"github.com/google/syzkaller/pkg/build"
17+
"github.com/google/syzkaller/pkg/instance"
18+
"github.com/google/syzkaller/pkg/mgrconfig"
19+
"github.com/google/syzkaller/pkg/osutil"
20+
"github.com/google/syzkaller/sys/targets"
1021
)
1122

1223
// TestPatch action does an in-tree kernel build in KernelScratchSrc dir,
@@ -36,5 +47,82 @@ type testResult struct {
3647
}
3748

3849
func testPatch(ctx *aflow.Context, args testArgs) (testResult, error) {
39-
return testResult{}, nil
50+
res := testResult{}
51+
// Always clean up the repository at the end of this action
52+
defer func() {
53+
osutil.RunCmd(time.Minute, args.KernelScratchSrc, "git", "checkout", "--", ".")
54+
}()
55+
56+
// Capture the current diff early on
57+
diff, err := osutil.RunCmd(time.Minute, args.KernelScratchSrc, "git", "diff")
58+
if err != nil {
59+
return res, aflow.FlowError(fmt.Errorf("capturing diff failed: %w\n%s", err, res.PatchDiff))
60+
}
61+
res.PatchDiff = string(diff)
62+
63+
if args.Type != "qemu" {
64+
return res, errors.New("only qemu VM type is supported")
65+
}
66+
67+
// Build the kernel
68+
if err := osutil.WriteFile(filepath.Join(args.KernelScratchSrc, ".config"), []byte(args.KernelConfig)); err != nil {
69+
return res, err
70+
}
71+
target := targets.List[targets.Linux][targets.AMD64]
72+
image := filepath.FromSlash(build.LinuxKernelImage(targets.AMD64))
73+
makeArgs := build.LinuxMakeArgs(target, targets.DefaultLLVMCompiler, targets.DefaultLLVMLinker,
74+
"ccache", args.KernelScratchSrc, runtime.NumCPU())
75+
makeArgs = append(makeArgs, "-s", path.Base(image))
76+
if out, err := osutil.RunCmd(time.Hour, args.KernelScratchSrc, "make", makeArgs...); err != nil {
77+
res.TestError = fmt.Sprintf("Make failed with %v:\n%v", err, string(out))
78+
return res, nil
79+
}
80+
81+
// Reproduce the crash
82+
var vmConfig map[string]any
83+
if err := json.Unmarshal(args.VM, &vmConfig); err != nil {
84+
return res, fmt.Errorf("failed to parse VM config: %w", err)
85+
}
86+
vmConfig["kernel"] = filepath.Join(args.KernelScratchSrc, filepath.FromSlash(build.LinuxKernelImage(targets.AMD64)))
87+
vmCfg, err := json.Marshal(vmConfig)
88+
if err != nil {
89+
return res, fmt.Errorf("failed to serialize VM config: %w", err)
90+
}
91+
92+
workdir, err := ctx.TempDir()
93+
if err != nil {
94+
return res, err
95+
}
96+
cfg := mgrconfig.DefaultValues()
97+
cfg.RawTarget = "linux/amd64"
98+
cfg.Workdir = workdir
99+
cfg.Syzkaller = args.Syzkaller
100+
cfg.KernelObj = args.KernelScratchSrc
101+
cfg.KernelSrc = args.KernelScratchSrc
102+
cfg.Image = args.Image
103+
cfg.Type = args.Type
104+
cfg.VM = vmCfg
105+
if err := mgrconfig.SetTargets(cfg); err != nil {
106+
return res, err
107+
}
108+
if err := mgrconfig.Complete(cfg); err != nil {
109+
return res, err
110+
}
111+
env, err := instance.NewEnv(cfg, nil, nil)
112+
if err != nil {
113+
return res, err
114+
}
115+
results, err := env.Test(1, nil, nil, []byte(args.ReproC))
116+
if err != nil {
117+
return res, err
118+
}
119+
if results[0].Error != nil {
120+
if crashErr := new(instance.CrashError); errors.As(results[0].Error, &crashErr) {
121+
res.TestError = fmt.Sprintf("Reproducing the crash reported: %v", string(crashErr.Report.Report))
122+
} else {
123+
res.TestError = fmt.Sprintf("Reproducing the crash failed with: %v", results[0].Error.Error())
124+
}
125+
}
126+
127+
return res, nil
40128
}

0 commit comments

Comments
 (0)