• Will Deacon's avatar
    iommu/io-pgtable-arm: Unmap and free table when overwriting with block · cf27ec93
    Will Deacon authored
    When installing a block mapping, we unconditionally overwrite a non-leaf
    PTE if we find one. However, this can cause a problem if the following
    sequence of events occur:
    
      (1) iommu_map called for a 4k (i.e. PAGE_SIZE) mapping at some address
          - We initialise the page table all the way down to a leaf entry
          - No TLB maintenance is required, because we're going from invalid
            to valid.
    
      (2) iommu_unmap is called on the mapping installed in (1)
          - We walk the page table to the final (leaf) entry and zero it
          - We only changed a valid leaf entry, so we invalidate leaf-only
    
      (3) iommu_map is called on the same address as (1), but this time for
          a 2MB (i.e. BLOCK_SIZE) mapping)
          - We walk the page table down to the penultimate level, where we
            find a table entry
          - We overwrite the table entry with a block mapping and return
            without any TLB maintenance and without freeing the memory used
            by the now-orphaned table.
    
    This last step can lead to a walk-cache caching the overwritten table
    entry, causing unexpected faults when the new mapping is accessed by a
    device. One way to fix this would be to collapse the page table when
    freeing the last page at a given level, but this would require expensive
    iteration on every map call. Instead, this patch detects the case when
    we are overwriting a table entry and explicitly unmaps the table first,
    which takes care of both freeing and TLB invalidation.
    
    Cc: <stable@vger.kernel.org>
    Reported-by: default avatarBrian Starkey <brian.starkey@arm.com>
    Tested-by: default avatarBrian Starkey <brian.starkey@arm.com>
    Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
    Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
    cf27ec93
io-pgtable-arm.c 27.6 KB