Hello Jiri, we have been analyzing the HW/Hypervisor-OS interface of device drivers and discovered bugs in the rocker driver that can be triggered from a malicious Hypervisor or PCI device.
The reason for analyzing these interfaces is that, technologies such as Intel's Trusted Domain Extensions [1] and AMD's Secure Nested Paging [2] change the threat model assumed by various Linux kernel subsystems. These technologies take the presence of a fully malicious hypervisor into account and aim to provide protection for virtual machines in such an environment. Executing at a higher privilege level than the guest kernel, the hypervisor was considered trustworthy in the past. Note that these issues are of little (or no) relevance in a "normal" virtualization setup, nevertheless we believe that it is required to fix them if TDX or SNP is used. Further, it is known that malicious PCI devices can be attached to the USB-C port in order to attack this interface [3] (if thunderbolt is not locked down). Therefore, all input received from the hypervisor or an external device should be carefully validated. We are aware that these threat-models are relatively new and many parts of the Linux kernel do not yet incorporate them. We are happy to provide more information if needed! [1] https://software.intel.com/content/www/us/en/develop/articles/intel-trust-domain-extensions.html [2] https://www.amd.com/en/processors/amd-secure-encrypted-virtualization [3] https://www.ndss-symposium.org/wp-content/uploads/2019/02/ndss2019_05A-1_Markettos_paper.pdf ################################################################### Bug1: Description: Oob array access on rocker->msix_entries, due to an integer overflow when evaluating ROCKER_MSIX_VEC_COUNT. The allocation size of the rocker->msix_entries array determined by the hardware https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L2684 https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L2691 A different hardware controlled variable port_count determines the maximum index for this array via https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_hw.h#L33 For a sufficiently large value of port count this calculation will cause an integer overflow, i.e. port_count == 0xffffffff will result in ROCKER_MSIX_VEC_COUNT(rocker->port_count) == 2, which is lower than e.g. ROCKER_MSIX_VEC_RESERVED0. Therefore, even though the number of reported msix_entries is checked against port count https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L2688 We found that for a value of port_count == -1/0xffffffff and msix_entries == 2 that check will not trigger. This leads to oob access on each invocation of rocker_msix_vector https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L96 Whenever the passed vector parameter is >= 2, e.g. https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L280 Patch: Cast to long in ROCKER_MSIX_VEC_COUNT Or check if port_count has a valid range in https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L2944 ################################################################### Bug2: Description: PTR read from dma controlled mem (desc_info) https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L572 https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L358 rocker->cmd_ring->desc is allocated as coherent dma memory https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L610 https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L444 And rocker->cmd_ring->desc_info[*].desc is set to point to desc structures in dma memory https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L453 When the device is removed the following functions are called Rocker_remove -> rocker_dma_rings_finie -> rocker_dma_cmd_ring_waits_free -> rocker_dma_cmd_wait_free Rocker_dma_cmd_wait_free invokes rocker_desc_cookie_ptr_get to initialize the pointer variable ‘wait’ with a device controlled value (as it is located in dma coherent memory). And passes that value to kfree. https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L572 https://github.com/torvalds/linux/blob/eccc876724927ff3b9ff91f36f7b6b159e948f0c/drivers/net/ethernet/rocker/rocker_main.c#L358 Similar issues arise in other locations of the driver.