github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/build/netbsd.go (about) 1 // Copyright 2018 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package build 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "os" 10 "path/filepath" 11 "runtime" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/google/syzkaller/pkg/mgrconfig" 17 "github.com/google/syzkaller/pkg/osutil" 18 "github.com/google/syzkaller/pkg/report" 19 "github.com/google/syzkaller/sys/targets" 20 "github.com/google/syzkaller/vm" 21 ) 22 23 type netbsd struct{} 24 25 func (ctx netbsd) build(params Params) (ImageDetails, error) { 26 const kernelName = "GENERIC_SYZKALLER" 27 confDir := fmt.Sprintf("%v/sys/arch/%v/conf", params.KernelDir, params.TargetArch) 28 compileDir := fmt.Sprintf("%v/sys/arch/%v/compile/obj/%v", params.KernelDir, params.TargetArch, kernelName) 29 30 if err := osutil.WriteFile(filepath.Join(confDir, kernelName), params.Config); err != nil { 31 return ImageDetails{}, err 32 } 33 34 // Clear the tools. 35 if _, err := osutil.RunCmd(5*time.Minute, params.KernelDir, "rm", "-rf", "obj/"); err != nil { 36 return ImageDetails{}, err 37 } 38 39 // Clear the build files. 40 if _, err := osutil.RunCmd(5*time.Minute, params.KernelDir, "rm", "-rf", compileDir); err != nil { 41 return ImageDetails{}, err 42 } 43 44 if strings.HasSuffix(params.Compiler, "clang++") { 45 // Build tools before building kernel. 46 if _, err := osutil.RunCmd(60*time.Minute, params.KernelDir, "./build.sh", "-m", params.TargetArch, 47 "-U", "-j"+strconv.Itoa(runtime.NumCPU()), "-V", "MKCTF=no", 48 "-V", "MKLLVM=yes", "-V", "MKGCC=no", "-V", "HAVE_LLVM=yes", "tools"); err != nil { 49 return ImageDetails{}, err 50 } 51 52 // Build kernel. 53 if _, err := osutil.RunCmd(20*time.Minute, params.KernelDir, "./build.sh", "-m", params.TargetArch, 54 "-U", "-j"+strconv.Itoa(runtime.NumCPU()), "-V", "MKCTF=no", 55 "-V", "MKLLVM=yes", "-V", "MKGCC=no", "-V", "HAVE_LLVM=yes", "kernel="+kernelName); err != nil { 56 return ImageDetails{}, err 57 } 58 } else if strings.HasSuffix(params.Compiler, "g++") { 59 if _, err := osutil.RunCmd(30*time.Minute, params.KernelDir, "./build.sh", "-m", params.TargetArch, 60 "-U", "-j"+strconv.Itoa(runtime.NumCPU()), "-V", "MKCTF=no", "tools"); err != nil { 61 return ImageDetails{}, err 62 } 63 64 if _, err := osutil.RunCmd(20*time.Minute, params.KernelDir, "./build.sh", "-m", params.TargetArch, 65 "-U", "-j"+strconv.Itoa(runtime.NumCPU()), "-V", "MKCTF=no", "kernel="+kernelName); err != nil { 66 return ImageDetails{}, err 67 } 68 } 69 70 for _, s := range []struct{ dir, src, dst string }{ 71 {compileDir, "netbsd.gdb", "obj/netbsd.gdb"}, 72 {params.UserspaceDir, "image", "image"}, 73 {params.UserspaceDir, "key", "key"}, 74 } { 75 fullSrc := filepath.Join(s.dir, s.src) 76 fullDst := filepath.Join(params.OutputDir, s.dst) 77 if err := osutil.CopyFile(fullSrc, fullDst); err != nil { 78 return ImageDetails{}, fmt.Errorf("failed to copy %v -> %v: %w", fullSrc, fullDst, err) 79 } 80 } 81 keyFile := filepath.Join(params.OutputDir, "key") 82 if err := os.Chmod(keyFile, 0600); err != nil { 83 return ImageDetails{}, fmt.Errorf("failed to chmod 0600 %v: %w", keyFile, err) 84 } 85 return ImageDetails{}, ctx.copyKernelToDisk(params.TargetArch, params.VMType, params.OutputDir, 86 filepath.Join(compileDir, "netbsd")) 87 } 88 89 func (ctx netbsd) clean(kernelDir, targetArch string) error { 90 _, err := osutil.RunCmd(10*time.Minute, kernelDir, "./build.sh", "-m", targetArch, 91 "-U", "-j"+strconv.Itoa(runtime.NumCPU()), "cleandir") 92 return err 93 } 94 95 // Copy the compiled kernel to the qemu disk image using ssh. 96 func (ctx netbsd) copyKernelToDisk(targetArch, vmType, outputDir, kernel string) error { 97 // Let's run in emulation mode - we don't need to run long and it's most compatible. 98 vmConfig := ` 99 { 100 "snapshot": false, 101 "mem": 1024, 102 "qemu_args": "" 103 }` 104 // Create config for booting the disk image. 105 target := targets.Get(targets.NetBSD, targetArch) 106 cfg := &mgrconfig.Config{ 107 Workdir: outputDir, 108 Image: filepath.Join(outputDir, "image"), 109 SSHKey: filepath.Join(outputDir, "key"), 110 SSHUser: "root", 111 Type: "qemu", 112 VM: json.RawMessage([]byte(vmConfig)), 113 Derived: mgrconfig.Derived{ 114 TargetOS: targets.NetBSD, 115 TargetArch: targetArch, 116 TargetVMArch: targetArch, 117 Timeouts: target.Timeouts(1), 118 SysTarget: target, 119 }, 120 } 121 // Create a VM pool. 122 pool, err := vm.Create(cfg, false) 123 if err != nil { 124 return fmt.Errorf("failed to create a VM Pool: %w", err) 125 } 126 // Create a new reporter instance. 127 reporter, err := report.NewReporter(cfg) 128 if err != nil { 129 return fmt.Errorf("failed to create a Reporter: %w", err) 130 } 131 // Create a VM instance (we need only one). 132 inst, err := pool.Create(0) 133 if err != nil { 134 return fmt.Errorf("failed to create the VM Instance: %w", err) 135 } 136 defer inst.Close() 137 // Copy the kernel into the disk image and replace it. 138 kernel, err = inst.Copy(kernel) 139 if err != nil { 140 return fmt.Errorf("error copying the kernel: %w", err) 141 } 142 if kernel != "/netbsd" { 143 return fmt.Errorf("kernel is copied into wrong location: %v", kernel) 144 } 145 commands := []string{"touch /fastboot"} // /fastboot file prevents disk check on start. 146 if vmType == "gce" { 147 commands = append(commands, []string{ 148 // We expect boot disk to be wd0a for the qemu (that's how qemu exposes -hda disk). 149 // GCE exposes boot disk as sd0a. 150 `sed -i 's#wd0#sd0#g' /etc/fstab`, 151 // GCE provides vioif0 interface. 152 `echo '!dhcpcd vioif0' > /etc/ifconfig.vioif0`, 153 `echo 'mtu 1460' >> /etc/ifconfig.vioif0`, 154 }...) 155 } 156 commands = append(commands, "mknod /dev/vhci c 355 0") 157 commands = append(commands, "sync") // Run sync so that the copied image is stored properly. 158 _, rep, err := inst.Run(time.Minute, reporter, strings.Join(commands, ";")) 159 if err != nil { 160 return fmt.Errorf("error syncing the instance %w", err) 161 } 162 // Make sure that the command has executed properly. 163 if rep != nil { 164 return fmt.Errorf("error executing sync: %v", rep.Title) 165 } 166 return nil 167 }