blob: 5d9263620747152201d1dfa746957d516b0f5ef8 [file] [log] [blame]
// Copyright 2018 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 build
import (
"encoding/json"
"fmt"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
"github.com/google/syzkaller/pkg/mgrconfig"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/pkg/report"
"github.com/google/syzkaller/vm"
)
type netbsd struct{}
func (ctx netbsd) build(targetArch, vmType, kernelDir, outputDir, compiler, userspaceDir,
cmdlineFile, sysctlFile string, config []byte) error {
const kernelName = "GENERIC_SYZKALLER"
confDir := fmt.Sprintf("%v/sys/arch/%v/conf", kernelDir, targetArch)
compileDir := fmt.Sprintf("%v/sys/arch/%v/compile/obj/%v", kernelDir, targetArch, kernelName)
// Compile the kernel with KASAN
conf := []byte(`
include "arch/amd64/conf/GENERIC"
options DEBUG
options LOCKDEBUG
makeoptions KASAN=1
options KASAN
no options SVS
options KASAN_PANIC
makeoptions KCOV=1
options KCOV
`)
if err := osutil.WriteFile(filepath.Join(confDir, kernelName), conf); err != nil {
return err
}
// Build tools before building kernel
if _, err := osutil.RunCmd(10*time.Minute, kernelDir, "./build.sh", "-m", targetArch,
"-U", "-u", "-j"+strconv.Itoa(runtime.NumCPU()), "-V", "MKCTF=no", "tools"); err != nil {
return err
}
// Build kernel
if _, err := osutil.RunCmd(10*time.Minute, kernelDir, "./build.sh", "-m", targetArch,
"-U", "-u", "-j"+strconv.Itoa(runtime.NumCPU()), "-V", "MKCTF=no", "kernel="+kernelName); err != nil {
return err
}
for _, s := range []struct{ dir, src, dst string }{
{compileDir, "netbsd.gdb", "obj/netbsd.gdb"},
{userspaceDir, "image", "image"},
{userspaceDir, "key", "key"},
} {
fullSrc := filepath.Join(s.dir, s.src)
fullDst := filepath.Join(outputDir, s.dst)
if err := osutil.CopyFile(fullSrc, fullDst); err != nil {
return fmt.Errorf("failed to copy %v -> %v: %v", fullSrc, fullDst, err)
}
}
return ctx.copyKernelToDisk(targetArch, vmType, outputDir, filepath.Join(compileDir, "netbsd"))
}
func (ctx netbsd) clean(kernelDir, targetArch string) error {
_, err := osutil.RunCmd(10*time.Minute, kernelDir, "./build.sh", "-m", targetArch,
"-U", "-j"+strconv.Itoa(runtime.NumCPU()), "cleandir")
return err
}
// Copy the compiled kernel to the qemu disk image using ssh.
func (ctx netbsd) copyKernelToDisk(targetArch, vmType, outputDir, kernel string) error {
vmConfig := `
{
"snapshot": false,
"mem": 1024
}`
// Create config for booting the disk image.
cfg := &mgrconfig.Config{
Workdir: outputDir,
Image: filepath.Join(outputDir, "image"),
SSHKey: filepath.Join(outputDir, "key"),
SSHUser: "root",
TargetOS: "netbsd",
TargetArch: targetArch,
TargetVMArch: targetArch,
Type: "qemu",
VM: json.RawMessage([]byte(vmConfig)),
}
// Create a VM pool.
pool, err := vm.Create(cfg, false)
if err != nil {
return fmt.Errorf("failed to create a VM Pool: %v", err)
}
// Create a new reporter instance.
reporter, err := report.NewReporter(cfg)
if err != nil {
return fmt.Errorf("failed to create a Reporter: %v", err)
}
// Create a VM instance (we need only one).
inst, err := pool.Create(0)
if err != nil {
return fmt.Errorf("failed to create the VM Instance: %v", err)
}
defer inst.Close()
// Copy the kernel into the disk image and replace it
kernel, err = inst.Copy(kernel)
if err != nil {
return fmt.Errorf("error copying the kernel: %v", err)
}
if kernel != "/netbsd" {
return fmt.Errorf("kernel is copied into wrong location: %v", kernel)
}
commands := []string{"touch /fastboot"} // /fastboot file prevents disk check on start.
if vmType == "gce" {
commands = append(commands, []string{
// We expect boot disk to be wd0a for the qemu (that's how qemu exposes -hda disk).
// GCE exposes boot disk as sd0a.
`sed -i 's#wd0#sd0#g' /etc/fstab`,
// GCE provides vioif0 interface.
`echo '!dhcpcd vioif0' > /etc/ifconfig.vioif0`,
`echo 'mtu 1460' >> /etc/ifconfig.vioif0`,
}...)
}
commands = append(commands, "sync") // Run sync so that the copied image is stored properly.
outc, errc, err := inst.Run(time.Minute, nil, strings.Join(commands, ";"))
if err != nil {
return fmt.Errorf("error syncing the instance %v", err)
}
// Make sure that the command has executed properly.
rep := inst.MonitorExecution(outc, errc, reporter, vm.ExitNormal)
if rep != nil {
return fmt.Errorf("error executing sync: %v", rep.Title)
}
return nil
}