Beispiel #1
0
  def ParseFiles(self, knowledge_base, pathspecs, filedescs):
    del knowledge_base  # Unused.

    # Each file gives us only partial information for a particular PCI device.
    # Iterate through all the files first to create a dictionary encapsulating
    # complete information for each of the PCI device on the system. We need
    # all information for a PCI device before a proto for it can be created.
    # We will store data in a dictionary of dictionaries that looks like this:
    # data = { '0000:7f:0d.0': { 'class': '0x088000',
    #                            'vendor': '0x8086',
    #                            'device': '0x0ee1' } }
    # The key is location of PCI device on system in extended B/D/F notation
    # and value is a dictionary containing filename:data pairs for each file
    # returned by artifact collection for that PCI device.

    # Extended B/D/F is of form "domain:bus:device.function". Compile a regex
    # so we can use it to skip parsing files that don't match it.
    hc = r"[0-9A-Fa-f]"
    bdf_regex = re.compile(r"^%s+:%s+:%s+\.%s+" % (hc, hc, hc, hc))

    # This will make sure that when a non-existing 'key' (PCI location)
    # is accessed for the first time a new 'key':{} pair is auto-created
    data = collections.defaultdict(dict)

    for pathspec, file_obj in zip(pathspecs, filedescs):
      filename = pathspec.Basename()
      # Location of PCI device is the name of parent directory of returned file.
      bdf = pathspec.Dirname().Basename()

      # Make sure we only parse files that are under a valid B/D/F folder
      if bdf_regex.match(bdf):
        # Remove newlines from all files except config. Config contains raw data
        # so we don't want to touch it even if it has a newline character.
        file_data = file_obj.read()
        if filename != "config":
          file_data = file_data.rstrip(b"\n")
        data[bdf][filename] = file_data

    # Now that we've captured all information for each PCI device. Let's convert
    # the dictionary into a list of PCIDevice protos.
    for bdf, bdf_filedata in iteritems(data):
      pci_device = rdf_client.PCIDevice()
      bdf_split = bdf.split(":")
      df_split = bdf_split[2].split(".")

      # We'll convert the hex into decimal to store in the protobuf.
      pci_device.domain = int(bdf_split[0], 16)
      pci_device.bus = int(bdf_split[1], 16)
      pci_device.device = int(df_split[0], 16)
      pci_device.function = int(df_split[1], 16)

      pci_device.class_id = bdf_filedata.get("class")
      pci_device.vendor = bdf_filedata.get("vendor")
      pci_device.vendor_device_id = bdf_filedata.get("device")
      pci_device.config = bdf_filedata.get("config")

      yield pci_device
Beispiel #2
0
    def testPCIDevicesInfoParser(self):
        """Ensure we can extract PCI devices info."""

        # Test when there's data for one PCI device only.
        test_data1 = {
            "/sys/bus/pci/devices/0000:00:01.0/vendor": b"0x0e00\n",
            "/sys/bus/pci/devices/0000:00:01.0/class": b"0x060400\n",
            "/sys/bus/pci/devices/0000:00:01.0/device": b"0x0e02\n",
            "/sys/bus/pci/devices/0000:00:01.0/config": b"0200"
        }
        device_1 = rdf_client.PCIDevice(domain=0,
                                        bus=0,
                                        device=1,
                                        function=0,
                                        class_id="0x060400",
                                        vendor="0x0e00",
                                        vendor_device_id="0x0e02",
                                        config=b"0200")
        parsed_results = self._ParsePCIDeviceTestData(test_data1)
        self._MatchPCIDeviceResultToExpected(parsed_results, [device_1])

        test_data2 = {
            "/sys/bus/pci/devices/0000:00:00.0/vendor":
            b"0x8086\n",
            "/sys/bus/pci/devices/0000:00:00.0/class":
            b"0x060000\n",
            "/sys/bus/pci/devices/0000:00:00.0/device":
            b"0x0e00\n",
            "/sys/bus/pci/devices/0000:00:00.0/config":
            (b"\xea\xe8\xe7\xbc\x7a\x84"
             b"\x91"),
        }
        device_2 = rdf_client.PCIDevice(domain=0,
                                        bus=0,
                                        device=0,
                                        function=0,
                                        class_id="0x060000",
                                        vendor="0x8086",
                                        vendor_device_id="0x0e00",
                                        config=b"\xea\xe8\xe7\xbcz\x84\x91")
        parsed_results = self._ParsePCIDeviceTestData(test_data2)
        self._MatchPCIDeviceResultToExpected(parsed_results, [device_2])

        # Test for when there's missing data.
        test_data3 = {
            "/sys/bus/pci/devices/0000:00:03.0/vendor": b"0x0e00\n",
            "/sys/bus/pci/devices/0000:00:03.0/config": b"0030"
        }
        device_3 = rdf_client.PCIDevice(domain=0,
                                        bus=0,
                                        device=3,
                                        function=0,
                                        vendor="0x0e00",
                                        config=b"0030")
        parsed_results = self._ParsePCIDeviceTestData(test_data3)
        self._MatchPCIDeviceResultToExpected(parsed_results, [device_3])

        # Test when data contains non-valid B/D/F folders/files.
        test_data4 = {
            "/sys/bus/pci/devices/0000:00:05.0/vendor": b"0x0e00\n",
            "/sys/bus/pci/devices/0000:00:05.0/class": b"0x060400\n",
            "/sys/bus/pci/devices/0000:00:05.0/device": b"0x0e02\n",
            "/sys/bus/pci/devices/0000:00:05.0/config": b"0200",
            "/sys/bus/pci/devices/crazyrandomfile/test1": b"test1",
            "/sys/bus/pci/devices/::./test2": b"test2",
            "/sys/bus/pci/devices/00:5.0/test3": b"test3"
        }
        device_4 = rdf_client.PCIDevice(domain=0,
                                        bus=0,
                                        device=5,
                                        function=0,
                                        class_id="0x060400",
                                        vendor="0x0e00",
                                        vendor_device_id="0x0e02",
                                        config=b"0200")
        parsed_results = self._ParsePCIDeviceTestData(test_data4)
        self._MatchPCIDeviceResultToExpected(parsed_results, [device_4])

        # Test when there's multiple PCI devices in the test_data.
        combined_data = test_data1.copy()
        combined_data.update(test_data3)
        combined_data.update(test_data4)
        combined_data.update(test_data2)
        parsed_results = self._ParsePCIDeviceTestData(combined_data)
        self._MatchPCIDeviceResultToExpected(
            parsed_results, [device_1, device_4, device_2, device_3])