]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
arm64: Ignore hardware dirty bit updates in ptep_set_wrprotect()
authorCatalin Marinas <catalin.marinas@arm.com>
Wed, 5 Jul 2017 09:59:42 +0000 (10:59 +0100)
committerKhalid Elmously <khalid.elmously@canonical.com>
Tue, 27 Feb 2018 16:32:17 +0000 (11:32 -0500)
ptep_set_wrprotect() is only called on CoW mappings which are private
(!VM_SHARED) with the pte either read-only (!PTE_WRITE && PTE_RDONLY) or
writable and software-dirty (PTE_WRITE && !PTE_RDONLY && PTE_DIRTY).
There is no race with the hardware update of the dirty state: clearing
of PTE_RDONLY when PTE_WRITE (a.k.a. PTE_DBM) is set. This patch removes
the code setting the software PTE_DIRTY bit in ptep_set_wrprotect() as
superfluous. A VM_WARN_ONCE is introduced in case the above logic is
wrong or the core mm code changes its use of ptep_set_wrprotect().

Reviewed-by: Will Deacon <will.deacon@arm.com>
Acked-by: Steve Capper <steve.capper@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
(cherry picked from commit 64c26841b34957ef8f33f7a9e8663aeee59c3ded)

CVE-2017-5753
CVE-2017-5715
CVE-2017-5754

Signed-off-by: Paolo Pisati <paolo.pisati@canonical.com>
Acked-by: Brad Figg <brad.figg@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
arch/arm64/include/asm/pgtable.h

index 64ef60f717bad09b8d3e3d1c0be9815fad99c484..62b62f4c39e89fadef686e4c954b46c12268a855 100644 (file)
@@ -634,23 +634,28 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 /*
- * ptep_set_wrprotect - mark read-only while trasferring potential hardware
- * dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit.
+ * ptep_set_wrprotect - mark read-only while preserving the hardware update of
+ * the Access Flag.
  */
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
 {
        pte_t old_pte, pte;
 
+       /*
+        * ptep_set_wrprotect() is only called on CoW mappings which are
+        * private (!VM_SHARED) with the pte either read-only (!PTE_WRITE &&
+        * PTE_RDONLY) or writable and software-dirty (PTE_WRITE &&
+        * !PTE_RDONLY && PTE_DIRTY); see is_cow_mapping() and
+        * protection_map[]. There is no race with the hardware update of the
+        * dirty state: clearing of PTE_RDONLY when PTE_WRITE (a.k.a. PTE_DBM)
+        * is set.
+        */
+       VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(*ptep),
+                    "%s: potential race with hardware DBM", __func__);
        pte = READ_ONCE(*ptep);
        do {
                old_pte = pte;
-               /*
-                * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
-                * clear), set the PTE_DIRTY bit.
-                */
-               if (pte_hw_dirty(pte))
-                       pte = pte_mkdirty(pte);
                pte = pte_wrprotect(pte);
                pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
                                               pte_val(old_pte), pte_val(pte));