示例#1
0
    def ParseMultiple(self, stats, file_objects, unused_knowledge_base):

        # 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 stat, file_obj in zip(stats, file_objects):
            filename = stat.pathspec.Basename()
            # Location of PCI device is the name of parent directory of returned file.
            bdf = stat.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("\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 data.iteritems():
            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
示例#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": "0x0e00\n",
            "/sys/bus/pci/devices/0000:00:01.0/class": "0x060400\n",
            "/sys/bus/pci/devices/0000:00:01.0/device": "0x0e02\n",
            "/sys/bus/pci/devices/0000:00:01.0/config": "0200"
        }
        device_1 = rdf_client.PCIDevice(domain=0,
                                        bus=0,
                                        device=1,
                                        function=0,
                                        class_id="0x060400",
                                        vendor="0x0e00",
                                        vendor_device_id="0x0e02",
                                        config="0200")
        parsed_results = self._ParsePCIDeviceTestData(test_data1)
        self._MatchPCIDeviceResultToExpected(parsed_results, [device_1])

        # Use raw bytes to test PCI device config works as expected.
        bytes2 = bytearray([234, 232, 231, 188, 122, 132, 145])
        test_data2 = {
            "/sys/bus/pci/devices/0000:00:00.0/vendor": "0x8086\n",
            "/sys/bus/pci/devices/0000:00:00.0/class": "0x060000\n",
            "/sys/bus/pci/devices/0000:00:00.0/device": "0x0e00\n",
            "/sys/bus/pci/devices/0000:00:00.0/config": bytes2
        }
        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": "0x0e00\n",
            "/sys/bus/pci/devices/0000:00:03.0/config": "0030"
        }
        device_3 = rdf_client.PCIDevice(domain=0,
                                        bus=0,
                                        device=3,
                                        function=0,
                                        vendor="0x0e00",
                                        config="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": "0x0e00\n",
            "/sys/bus/pci/devices/0000:00:05.0/class": "0x060400\n",
            "/sys/bus/pci/devices/0000:00:05.0/device": "0x0e02\n",
            "/sys/bus/pci/devices/0000:00:05.0/config": "0200",
            "/sys/bus/pci/devices/crazyrandomfile/test1": "test1",
            "/sys/bus/pci/devices/::./test2": "test2",
            "/sys/bus/pci/devices/00:5.0/test3": "test3"
        }
        device_4 = rdf_client.PCIDevice(domain=0,
                                        bus=0,
                                        device=5,
                                        function=0,
                                        class_id="0x060400",
                                        vendor="0x0e00",
                                        vendor_device_id="0x0e02",
                                        config="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])