Пример #1
0
  def _setup_fuzzer_and_device(self):
    """ Build a Fuzzer object based on the QEMU values.
    Call this only after setup_qemu_values()"""
    fuchsia_pkey_path = environment.get_value('FUCHSIA_PKEY_PATH')
    fuchsia_portnum = environment.get_value('FUCHSIA_PORTNUM')
    fuchsia_resources_dir = environment.get_value('FUCHSIA_RESOURCES_DIR')
    if (not fuchsia_pkey_path or not fuchsia_portnum or
        not fuchsia_resources_dir):
      raise fuchsia.errors.FuchsiaConfigError(
          ('FUCHSIA_PKEY_PATH, FUCHSIA_PORTNUM, or FUCHSIA_RESOURCES_DIR was '
           'not set'))
    fuchsia_resources_dir_plus_build = os.path.join(fuchsia_resources_dir,
                                                    self.FUCHSIA_BUILD_REL_PATH)
    self.host = Host.from_dir(fuchsia_resources_dir_plus_build)
    self.device = Device(self.host, 'localhost', fuchsia_portnum)
    self.device.set_ssh_option('StrictHostKeyChecking no')
    self.device.set_ssh_option('UserKnownHostsFile=/dev/null')
    self.device.set_ssh_identity(fuchsia_pkey_path)

    # Fuchsia fuzzer names have the format {package_name}/{binary_name}.
    package, target = environment.get_value('FUZZ_TARGET').split('/')
    test_data_dir = os.path.join(fuchsia_resources_dir_plus_build,
                                 self.FUZZER_TEST_DATA_REL_PATH, package,
                                 target)
    self.fuzzer = Fuzzer(
        self.device, package, target, output=test_data_dir, foreground=True)
Пример #2
0
    def __init__(self, executable_path, default_args=None):
        fuchsia_pkey_path = environment.get_value('FUCHSIA_PKEY_PATH')
        fuchsia_portnum = environment.get_value('FUCHSIA_PORTNUM')
        fuchsia_resources_dir = environment.get_value('FUCHSIA_RESOURCES_DIR')
        if (not fuchsia_pkey_path or not fuchsia_portnum
                or not fuchsia_resources_dir):
            raise fuchsia.errors.FuchsiaConfigError((
                'FUCHSIA_PKEY_PATH, FUCHSIA_PORTNUM, or FUCHSIA_RESOURCES_DIR was '
                'not set'))
        fuchsia_resources_dir_plus_build = os.path.join(
            fuchsia_resources_dir, self.FUCHSIA_BUILD_REL_PATH)
        self.host = Host.from_dir(fuchsia_resources_dir_plus_build)
        self.device = Device(self.host, 'localhost', fuchsia_portnum)
        self.device.set_ssh_option('StrictHostKeyChecking no')
        self.device.set_ssh_option('UserKnownHostsFile=/dev/null')
        self.device.set_ssh_identity(fuchsia_pkey_path)
        # Fuchsia fuzzer names have the format {package_name}/{binary_name}.
        package, target = environment.get_value('FUZZ_TARGET').split('/')
        test_data_dir = os.path.join(fuchsia_resources_dir_plus_build,
                                     self.FUZZER_TEST_DATA_REL_PATH, package,
                                     target)
        self.fuzzer = Fuzzer(self.device,
                             package,
                             target,
                             output=test_data_dir,
                             foreground=True)

        super(FuchsiaQemuLibFuzzerRunner,
              self).__init__(executable_path=executable_path,
                             default_args=default_args)
Пример #3
0
    def _setup_device_and_fuzzer(self):
        """Build a Device and Fuzzer object based on QEMU's settings."""
        # These environment variables are set when start_qemu is run.
        # We need them in order to ssh / otherwise communicate with the VM.
        fuchsia_pkey_path = environment.get_value('FUCHSIA_PKEY_PATH')
        fuchsia_portnum = environment.get_value('FUCHSIA_PORTNUM')
        fuchsia_resources_dir = environment.get_value('FUCHSIA_RESOURCES_DIR')
        if (not fuchsia_pkey_path or not fuchsia_portnum
                or not fuchsia_resources_dir):
            raise fuchsia.errors.FuchsiaConfigError((
                'FUCHSIA_PKEY_PATH, FUCHSIA_PORTNUM, or FUCHSIA_RESOURCES_DIR was '
                'not set'))

        # Fuzzer objects communicate with the VM via a Device object,
        # which we set up here.
        fuchsia_resources_dir_plus_build = os.path.join(
            fuchsia_resources_dir, self.FUCHSIA_BUILD_REL_PATH)
        self.host = Host.from_dir(fuchsia_resources_dir_plus_build)
        self.device = Device(self.host, 'localhost', fuchsia_portnum)
        self.device.set_ssh_option('StrictHostKeyChecking no')
        self.device.set_ssh_option('UserKnownHostsFile=/dev/null')
        self.device.set_ssh_identity(fuchsia_pkey_path)

        # Fuchsia fuzzer names have the format {package_name}/{binary_name}.
        package, target = self.executable_path.split('/')
        test_data_dir = os.path.join(fuchsia_resources_dir_plus_build,
                                     self.FUZZER_TEST_DATA_REL_PATH, package,
                                     target)

        # Finally, we set up the Fuzzer object itself, which will run our fuzzer!
        self.fuzzer = Fuzzer(self.device,
                             package,
                             target,
                             output=test_data_dir,
                             foreground=True)
Пример #4
0
 def __init__(self, executable_path, default_args=None):
     fuchsia_pkey_path = environment.get_value('FUCHSIA_PKEY_PATH')
     fuchsia_portnum = environment.get_value('FUCHSIA_PORTNUM')
     fuchsia_resources_dir = environment.get_value('FUCHSIA_RESOURCES_DIR')
     if (not fuchsia_pkey_path or not fuchsia_portnum
             or not fuchsia_resources_dir):
         raise fuchsia.errors.FuchsiaConfigError((
             'FUCHSIA_PKEY_PATH, FUCHSIA_PORTNUM, or FUCHSIA_RESOURCES_DIR was '
             'not set'))
     self.host = Host.from_dir(
         os.path.join(fuchsia_resources_dir, self.FUCHSIA_BUILD_REL_PATH))
     self.device = Device(self.host, 'localhost', fuchsia_portnum)
     # Fuchsia fuzzer names have the format {package_name}/{binary_name}.
     # TODO(ochang): Properly handle fuzzers with '/' in the binary name.
     package, target = environment.get_value('FUZZ_TARGET').split('/')
     self.fuzzer = Fuzzer(self.device, package, target)
     self.device.set_ssh_option('StrictHostKeyChecking no')
     self.device.set_ssh_option('UserKnownHostsFile=/dev/null')
     self.device.set_ssh_identity(fuchsia_pkey_path)
     super(FuchsiaQemuLibFuzzerRunner,
           self).__init__(executable_path=executable_path,
                          default_args=default_args)
Пример #5
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)
Пример #6
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
Пример #7
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)