Exemple #1
0
def setup_qemu_values(initial_setup=True):
  """Sets up and runs a QEMU VM in the background.
  Returns a process.Popen object.
  Does not block the calling process, and teardown must be handled by the
  caller (use .kill()).
  Fuchsia fuzzers assume a QEMU VM is running; call this routine prior to
  beginning Fuchsia fuzzing tasks.
  This initialization routine assumes the following layout for
  fuchsia_resources_dir:

  * /qemu-for-fuchsia/*
  * /.ssh/*
  * target/x64/fvm.blk
  * target/x64/fuchsia.zbi
  * target/x64/multiboot.bin

  * build/out/default/fuzzers.json
  * build/out/default/ids.txt
  * build/out/default.zircon/tools/*
  * build/zircon/prebuilt/downloads/symbolize
  * build/buildtools/linux-x64/clang/bin/llvm-symbolizer"""

  # First download the Fuchsia resources locally.
  fuchsia_resources_dir = environment.get_value('FUCHSIA_RESOURCES_DIR')
  if not fuchsia_resources_dir:
    raise errors.FuchsiaConfigError('Could not find FUCHSIA_RESOURCES_DIR')

  # Then, save paths for necessary commands later.
  qemu_path = os.path.join(fuchsia_resources_dir, 'qemu-for-fuchsia', 'bin',
                           'qemu-system-x86_64')
  os.chmod(qemu_path, 0o550)
  kernel_path = os.path.join(fuchsia_resources_dir, 'target', 'x64',
                             'multiboot.bin')
  os.chmod(kernel_path, 0o644)
  pkey_path = os.path.join(fuchsia_resources_dir, '.ssh', 'pkey')
  os.chmod(pkey_path, 0o400)
  sharefiles_path = os.path.join(fuchsia_resources_dir, 'qemu-for-fuchsia',
                                 'share', 'qemu')
  drive_path = os.path.join(fuchsia_resources_dir, 'target', 'x64', 'fvm.blk')
  os.chmod(drive_path, 0o644)
  fuchsia_zbi = os.path.join(fuchsia_resources_dir, 'target', 'x64',
                             'fuchsia.zbi')
  initrd_path = os.path.join(fuchsia_resources_dir, 'fuchsia-ssh.zbi')

  # Perform some more initiailization steps.
  # Only do these the first time you run QEMU after downloading the build.
  if initial_setup:
    extend_fvm(fuchsia_resources_dir, drive_path)
    add_keys_to_zbi(fuchsia_resources_dir, initrd_path, fuchsia_zbi)

  # Get a free port for the VM, so we can SSH in later.
  tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  tcp.bind(('localhost', 0))
  _, port = tcp.getsockname()
  tcp.close()
  # Fuzzing jobs that SSH into the QEMU VM need access to this env var.
  environment.set_value('FUCHSIA_PORTNUM', port)
  environment.set_value('FUCHSIA_RESOURCES_DIR', fuchsia_resources_dir)

  # yapf: disable
  qemu_args = [
      '-m', '2048',
      '-nographic',
      '-kernel', kernel_path,
      '-initrd', initrd_path,
      '-smp', '4',
      '-drive', 'file=' + drive_path + ',format=raw,if=none,id=blobstore',
      '-device', 'virtio-blk-pci,drive=blobstore',
      '-monitor', 'none',
      '-append', '"kernel.serial=legacy TERM=dumb"',
      '-machine', 'q35',
      '-display', 'none',
      '-netdev',
      ('user,id=net0,net=192.168.3.0/24,dhcpstart=192.168.3.9,'
       'host=192.168.3.2,hostfwd=tcp::') + str(port) + '-:22',
      '-device', 'e1000,netdev=net0,mac=52:54:00:63:5e:7b',
      '-L', sharefiles_path
  ]
  # yapf: enable

  # Detecing KVM is tricky, so use an environment variable to determine whether
  # to turn it on or not.
  if environment.get_value('FUCHSIA_USE_KVM'):
    qemu_args.extend(['-cpu', 'host,migratable=no'])
    qemu_args.append('-enable-kvm')
  else:
    # Can't use host CPU since we don't necessarily have KVM on the machine.
    # Emulate a Haswell CPU with a few feature toggles. This mirrors the most
    # common configuration for Fuchsia VMs when using in-tree tools.
    qemu_args.extend(['-cpu', 'Haswell,+smap,-check,-fsgsbase'])

  # Get the list of fuzzers for ClusterFuzz to choose from.
  host = Host.from_dir(
      os.path.join(fuchsia_resources_dir, 'build', 'out', 'default'))
  Device(host, 'localhost', str(port))
  Fuzzer.filter(host.fuzzers, '')

  # Fuzzing jobs that SSH into the QEMU VM need access to this env var.
  environment.set_value('FUCHSIA_PKEY_PATH', pkey_path)
  return qemu_path, qemu_args
Exemple #2
0
    def create(self):
        """Configures a QEMU process which can subsequently be `run`.

    Assumes that initial_qemu_setup was already called exactly once.
    """
        qemu_vars = _fetch_qemu_vars()

        # Get a free port for the VM, so we can SSH in later.
        tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        tcp.bind(('localhost', 0))
        _, port = tcp.getsockname()
        tcp.close()
        # Fuzzing jobs that SSH into the QEMU VM need access to this env var.
        environment.set_value('FUCHSIA_PORTNUM', port)
        environment.set_value('FUCHSIA_RESOURCES_DIR',
                              qemu_vars['fuchsia_resources_dir'])

        # yapf: disable
        qemu_args = [
            '-m', '3072',
            '-nographic',
            '-kernel', qemu_vars['kernel_path'],
            '-initrd', qemu_vars['initrd_path'],
            '-smp', '4',
            '-drive',
            ('file=' + qemu_vars['drive_path'] + ',format=raw,if=none,'
             'id=blobstore'),
            '-device', 'virtio-blk-pci,drive=blobstore',
            '-monitor', 'none',
            '-append', 'kernel.serial=legacy TERM=dumb',
            '-machine', 'q35',
            '-display', 'none',
            '-netdev',
            ('user,id=net0,net=192.168.3.0/24,dhcpstart=192.168.3.9,'
             'host=192.168.3.2,hostfwd=tcp::') + str(port) + '-:22',
            '-device', 'e1000,netdev=net0,mac=52:54:00:63:5e:7b',
            '-L', qemu_vars['sharefiles_path']
        ]
        # yapf: enable

        # Detecting KVM is tricky, so use an environment variable to determine
        # whether to turn it on or not.
        if environment.get_value('FUCHSIA_USE_KVM'):
            # In builds before fxrev.dev/375343, a bug prevents booting with newer
            # versions of KVM. On some of these older builds,
            # `kernel.x86.disable-spec-mitigations` also doesn't work as
            # expected, so we work around this by selecting a CPU type where the
            # speculation mitigation will not applied.
            if environment.get_value('APP_REVISION') < 20200414210423:
                qemu_args.extend(['-cpu', 'Opteron_G5,+invtsc'])
            else:
                qemu_args.extend(['-cpu', 'host,migratable=no,+invtsc'])
            qemu_args.append('-enable-kvm')
        else:
            # Can't use host CPU since we don't necessarily have KVM on the machine.
            # Emulate a Haswell CPU with a few feature toggles. This mirrors the most
            # common configuration for Fuchsia VMs when using in-tree tools.
            qemu_args.extend(['-cpu', 'Haswell,+smap,-check,-fsgsbase'])

        # Get the list of fuzzers for ClusterFuzz to choose from.
        host = Host.from_dir(
            os.path.join(qemu_vars['fuchsia_resources_dir'], 'build', 'out',
                         'default'))
        Device(host, 'localhost', str(port))
        Fuzzer.filter(host.fuzzers, '')

        # Fuzzing jobs that SSH into the QEMU VM need access to this env var.
        environment.set_value('FUCHSIA_PKEY_PATH', qemu_vars['pkey_path'])
        logs.log('Ready to run QEMU. Command: ' + qemu_vars['qemu_path'] +
                 ' ' + ' '.join(shlex.quote(arg) for arg in qemu_args))
        self.process_runner = new_process.ProcessRunner(
            qemu_vars['qemu_path'], qemu_args)
Exemple #3
0
    def create(self):
        """Configures a QEMU process which can subsequently be `run`.

        Assumes that initial_qemu_setup was already called exactly once.
        """
        qemu_vars = _fetch_qemu_vars()

        # Get a free port for the VM, so we can SSH in later.
        tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        tcp.bind(("localhost", 0))
        _, port = tcp.getsockname()
        tcp.close()
        # Fuzzing jobs that SSH into the QEMU VM need access to this env var.
        environment.set_value("FUCHSIA_PORTNUM", port)
        environment.set_value("FUCHSIA_RESOURCES_DIR",
                              qemu_vars["fuchsia_resources_dir"])

        # yapf: disable
        qemu_args = [
            '-m', '3072',
            '-nographic',
            '-kernel', qemu_vars['kernel_path'],
            '-initrd', qemu_vars['initrd_path'],
            '-smp', '4',
            '-drive',
            ('file=' + qemu_vars['drive_path'] + ',format=raw,if=none,'
             'id=blobstore'),
            '-device', 'virtio-blk-pci,drive=blobstore',
            '-monitor', 'none',
            '-append', 'kernel.serial=legacy TERM=dumb',
            '-machine', 'q35',
            '-display', 'none',
            '-netdev',
            ('user,id=net0,net=192.168.3.0/24,dhcpstart=192.168.3.9,'
             'host=192.168.3.2,hostfwd=tcp::') + str(port) + '-:22',
            '-device', 'e1000,netdev=net0,mac=52:54:00:63:5e:7b',
            '-L', qemu_vars['sharefiles_path']
        ]
        # yapf: enable

        # Detecing KVM is tricky, so use an environment variable to determine
        # whether to turn it on or not.
        if environment.get_value("FUCHSIA_USE_KVM"):
            qemu_args.extend(["-cpu", "host,migratable=no"])
            qemu_args.append("-enable-kvm")
        else:
            # Can't use host CPU since we don't necessarily have KVM on the machine.
            # Emulate a Haswell CPU with a few feature toggles. This mirrors the most
            # common configuration for Fuchsia VMs when using in-tree tools.
            qemu_args.extend(["-cpu", "Haswell,+smap,-check,-fsgsbase"])

        # Get the list of fuzzers for ClusterFuzz to choose from.
        host = Host.from_dir(
            os.path.join(qemu_vars["fuchsia_resources_dir"], "build", "out",
                         "default"))
        Device(host, "localhost", str(port))
        Fuzzer.filter(host.fuzzers, "")

        # Fuzzing jobs that SSH into the QEMU VM need access to this env var.
        environment.set_value("FUCHSIA_PKEY_PATH", qemu_vars["pkey_path"])
        logs.log("Ready to run QEMU. Command: " + qemu_vars["qemu_path"] +
                 " " + str(qemu_args))
        self.process_runner = new_process.ProcessRunner(
            qemu_vars["qemu_path"], qemu_args)