@@ -5,8 +5,19 @@ package crash
55
66import (
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
3849func 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