• James Houghton's avatar
    arm64: mm: Always make sw-dirty PTEs hw-dirty in pte_modify · 3c069607
    James Houghton authored
    It is currently possible for a userspace application to enter an
    infinite page fault loop when using HugeTLB pages implemented with
    contiguous PTEs when HAFDBS is not available. This happens because:
    
    1. The kernel may sometimes write PTEs that are sw-dirty but hw-clean
       (PTE_DIRTY | PTE_RDONLY | PTE_WRITE).
    
    2. If, during a write, the CPU uses a sw-dirty, hw-clean PTE in handling
       the memory access on a system without HAFDBS, we will get a page
       fault.
    
    3. HugeTLB will check if it needs to update the dirty bits on the PTE.
       For contiguous PTEs, it will check to see if the pgprot bits need
       updating. In this case, HugeTLB wants to write a sequence of
       sw-dirty, hw-dirty PTEs, but it finds that all the PTEs it is about
       to overwrite are all pte_dirty() (pte_sw_dirty() => pte_dirty()),
       so it thinks no update is necessary.
    
    We can get the kernel to write a sw-dirty, hw-clean PTE with the
    following steps (showing the relevant VMA flags and pgprot bits):
    
    i.   Create a valid, writable contiguous PTE.
           VMA vmflags:     VM_SHARED | VM_READ | VM_WRITE
           VMA pgprot bits: PTE_RDONLY | PTE_WRITE
           PTE pgprot bits: PTE_DIRTY | PTE_WRITE
    
    ii.  mprotect the VMA to PROT_NONE.
           VMA vmflags:     VM_SHARED
           VMA pgprot bits: PTE_RDONLY
           PTE pgprot bits: PTE_DIRTY | PTE_RDONLY
    
    iii. mprotect the VMA back to PROT_READ | PROT_WRITE.
           VMA vmflags:     VM_SHARED | VM_READ | VM_WRITE
           VMA pgprot bits: PTE_RDONLY | PTE_WRITE
           PTE pgprot bits: PTE_DIRTY | PTE_WRITE | PTE_RDONLY
    
    Make it impossible to create a writeable sw-dirty, hw-clean PTE with
    pte_modify(). Such a PTE should be impossible to create, and there may
    be places that assume that pte_dirty() implies pte_hw_dirty().
    Signed-off-by: default avatarJames Houghton <jthoughton@google.com>
    Fixes: 031e6e6b ("arm64: hugetlb: Avoid unnecessary clearing in huge_ptep_set_access_flags")
    Cc: <stable@vger.kernel.org>
    Acked-by: default avatarWill Deacon <will@kernel.org>
    Reviewed-by: default avatarRyan Roberts <ryan.roberts@arm.com>
    Link: https://lore.kernel.org/r/20231204172646.2541916-3-jthoughton@google.comSigned-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
    3c069607
pgtable.h 31.9 KB