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  }