• Robin Murphy's avatar
    iommu/vt-d: Fix scatterlist offset handling · 29a90b70
    Robin Murphy authored
    The intel-iommu DMA ops fail to correctly handle scatterlists where
    sg->offset is greater than PAGE_SIZE - the IOVA allocation is computed
    appropriately based on the page-aligned portion of the offset, but the
    mapping is set up relative to sg->page, which means it fails to actually
    cover the whole buffer (and in the worst case doesn't cover it at all):
    
        (sg->dma_address + sg->dma_len) ----+
        sg->dma_address ---------+          |
        iov_pfn------+           |          |
                     |           |          |
                     v           v          v
    iova:   a        b        c        d        e        f
            |--------|--------|--------|--------|--------|
                              <...calculated....>
                     [_____mapped______]
    pfn:    0        1        2        3        4        5
            |--------|--------|--------|--------|--------|
                     ^           ^          ^
                     |           |          |
        sg->page ----+           |          |
        sg->offset --------------+          |
        (sg->offset + sg->length) ----------+
    
    As a result, the caller ends up overrunning the mapping into whatever
    lies beyond, which usually goes badly:
    
    [  429.645492] DMAR: DRHD: handling fault status reg 2
    [  429.650847] DMAR: [DMA Write] Request device [02:00.4] fault addr f2682000 ...
    
    Whilst this is a fairly rare occurrence, it can happen from the result
    of intermediate scatterlist processing such as scatterwalk_ffwd() in the
    crypto layer. Whilst that particular site could be fixed up, it still
    seems worthwhile to bring intel-iommu in line with other DMA API
    implementations in handling this robustly.
    
    To that end, fix the intel_map_sg() path to line up the mapping
    correctly (in units of MM pages rather than VT-d pages to match the
    aligned_nrpages() calculation) regardless of the offset, and use
    sg_phys() consistently for clarity.
    Reported-by: default avatarHarsh Jain <Harsh@chelsio.com>
    Signed-off-by: default avatarRobin Murphy <robin.murphy@arm.com>
    Reviewed by: Ashok Raj <ashok.raj@intel.com>
    Tested by: Jacob Pan <jacob.jun.pan@intel.com>
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
    29a90b70
intel-iommu.c 137 KB