From f486078ac5d3eca51b34d2fdedeeba2a729f6296 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Sun, 26 May 2024 17:13:38 -0400 Subject: vm/bhyve: add support for the slirp network backend bhyve recently grew support for using libslirp (from QEMU) as the networking backend, which is useful for syzkaller since it requires no configuration on the host. This patch causes syz-manager to make use of the slirp backend when no VM bridge is configured. --- vm/bhyve/bhyve.go | 93 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 30 deletions(-) (limited to 'vm/bhyve') diff --git a/vm/bhyve/bhyve.go b/vm/bhyve/bhyve.go index c3b53e053..1570b7939 100644 --- a/vm/bhyve/bhyve.go +++ b/vm/bhyve/bhyve.go @@ -25,7 +25,7 @@ func init() { } type Config struct { - Bridge string `json:"bridge"` // name of network bridge device + Bridge string `json:"bridge"` // name of network bridge device, optional Count int `json:"count"` // number of VMs to use CPU int `json:"cpu"` // number of VM vCPU HostIP string `json:"hostip"` // VM host IP address @@ -39,19 +39,21 @@ type Pool struct { } type instance struct { - cfg *Config - snapshot string - tapdev string - image string - debug bool - os string - sshkey string - sshuser string - sshhost string - merger *vmimpl.OutputMerger - vmName string - bhyve *exec.Cmd - consolew io.WriteCloser + cfg *Config + snapshot string + tapdev string + port int + forwardPort int + image string + debug bool + os string + sshkey string + sshuser string + sshhost string + merger *vmimpl.OutputMerger + vmName string + bhyve *exec.Cmd + consolew io.WriteCloser } var ipRegex = regexp.MustCompile(`bound to (([0-9]+\.){3}[0-9]+) `) @@ -129,15 +131,17 @@ func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) { return nil, err } - tapdev, err := osutil.RunCmd(time.Minute, "", "ifconfig", "tap", "create") - if err != nil { - inst.Close() - return nil, err - } - inst.tapdev = tapRegex.FindString(string(tapdev)) - if _, err := osutil.RunCmd(time.Minute, "", "ifconfig", inst.cfg.Bridge, "addm", inst.tapdev); err != nil { - inst.Close() - return nil, err + if inst.cfg.Bridge != "" { + tapdev, err := osutil.RunCmd(time.Minute, "", "ifconfig", "tap", "create") + if err != nil { + inst.Close() + return nil, err + } + inst.tapdev = tapRegex.FindString(string(tapdev)) + if _, err := osutil.RunCmd(time.Minute, "", "ifconfig", inst.cfg.Bridge, "addm", inst.tapdev); err != nil { + inst.Close() + return nil, err + } } if err := inst.Boot(); err != nil { @@ -165,13 +169,22 @@ func (inst *instance) Boot() error { return err } + netdev := "" + if inst.tapdev != "" { + inst.port = 22 + netdev = inst.tapdev + } else { + inst.port = vmimpl.UnusedTCPPort() + netdev = fmt.Sprintf("slirp,hostfwd=tcp:127.0.0.1:%v-:22", inst.port) + } + bhyveArgs := []string{ "-H", "-A", "-P", "-c", fmt.Sprintf("%d", inst.cfg.CPU), "-m", inst.cfg.Mem, "-s", "0:0,hostbridge", "-s", "1:0,lpc", - "-s", fmt.Sprintf("2:0,virtio-net,%v", inst.tapdev), + "-s", fmt.Sprintf("2:0,virtio-net,%v", netdev), "-s", fmt.Sprintf("3:0,virtio-blk,%v", inst.image), "-l", "com1,stdio", inst.vmName, @@ -238,7 +251,11 @@ func (inst *instance) Boot() error { select { case ip := <-ipch: - inst.sshhost = ip + if inst.tapdev != "" { + inst.sshhost = ip + } else { + inst.sshhost = "localhost" + } case <-inst.merger.Err: bootOutputStop <- true <-bootOutputStop @@ -250,7 +267,7 @@ func (inst *instance) Boot() error { } if err := vmimpl.WaitForSSH(inst.debug, 10*time.Minute, inst.sshhost, - inst.sshkey, inst.sshuser, inst.os, 22, nil, false); err != nil { + inst.sshkey, inst.sshuser, inst.os, inst.port, nil, false); err != nil { bootOutputStop <- true <-bootOutputStop return vmimpl.MakeBootError(err, bootOutput) @@ -280,12 +297,23 @@ func (inst *instance) Close() { } func (inst *instance) Forward(port int) (string, error) { - return fmt.Sprintf("%v:%v", inst.cfg.HostIP, port), nil + if inst.tapdev != "" { + return fmt.Sprintf("%v:%v", inst.cfg.HostIP, port), nil + } else { + if port == 0 { + return "", fmt.Errorf("vm/bhyve: forward port is zero") + } + if inst.forwardPort != 0 { + return "", fmt.Errorf("vm/bhyve: forward port is already set") + } + inst.forwardPort = port + return fmt.Sprintf("localhost:%v", port), nil + } } func (inst *instance) Copy(hostSrc string) (string, error) { vmDst := filepath.Join("/root", filepath.Base(hostSrc)) - args := append(vmimpl.SCPArgs(inst.debug, inst.sshkey, 22, false), + args := append(vmimpl.SCPArgs(inst.debug, inst.sshkey, inst.port, false), hostSrc, inst.sshuser+"@"+inst.sshhost+":"+vmDst) if inst.debug { log.Logf(0, "running command: scp %#v", args) @@ -305,8 +333,13 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin } inst.merger.Add("ssh", rpipe) - args := append(vmimpl.SSHArgs(inst.debug, inst.sshkey, 22, false), - inst.sshuser+"@"+inst.sshhost, command) + sshargs := []string{} + if inst.forwardPort != 0 { + sshargs = vmimpl.SSHArgsForward(inst.debug, inst.sshkey, inst.port, inst.forwardPort, false) + } else { + sshargs = vmimpl.SSHArgs(inst.debug, inst.sshkey, inst.port, false) + } + args := append(sshargs, inst.sshuser+"@"+inst.sshhost, command) if inst.debug { log.Logf(0, "running command: ssh %#v", args) } -- cgit mrf-deployment