| From aa57157be69fb599bd4c38a4b75c5aad74a60ec0 Mon Sep 17 00:00:00 2001 |
| From: Catalin Marinas <catalin.marinas@arm.com> |
| Date: Tue, 29 Oct 2019 15:30:51 +0000 |
| Subject: arm64: Ensure VM_WRITE|VM_SHARED ptes are clean by default |
| |
| From: Catalin Marinas <catalin.marinas@arm.com> |
| |
| commit aa57157be69fb599bd4c38a4b75c5aad74a60ec0 upstream. |
| |
| Shared and writable mappings (__S.1.) should be clean (!dirty) initially |
| and made dirty on a subsequent write either through the hardware DBM |
| (dirty bit management) mechanism or through a write page fault. A clean |
| pte for the arm64 kernel is one that has PTE_RDONLY set and PTE_DIRTY |
| clear. |
| |
| The PAGE_SHARED{,_EXEC} attributes have PTE_WRITE set (PTE_DBM) and |
| PTE_DIRTY clear. Prior to commit 73e86cb03cf2 ("arm64: Move PTE_RDONLY |
| bit handling out of set_pte_at()"), it was the responsibility of |
| set_pte_at() to set the PTE_RDONLY bit and mark the pte clean if the |
| software PTE_DIRTY bit was not set. However, the above commit removed |
| the pte_sw_dirty() check and the subsequent setting of PTE_RDONLY in |
| set_pte_at() while leaving the PAGE_SHARED{,_EXEC} definitions |
| unchanged. The result is that shared+writable mappings are now dirty by |
| default |
| |
| Fix the above by explicitly setting PTE_RDONLY in PAGE_SHARED{,_EXEC}. |
| In addition, remove the superfluous PTE_DIRTY bit from the kernel PROT_* |
| attributes. |
| |
| Fixes: 73e86cb03cf2 ("arm64: Move PTE_RDONLY bit handling out of set_pte_at()") |
| Cc: <stable@vger.kernel.org> # 4.14.x- |
| Cc: Will Deacon <will@kernel.org> |
| Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> |
| Signed-off-by: Will Deacon <will@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/arm64/include/asm/pgtable-prot.h | 15 ++++++++------- |
| 1 file changed, 8 insertions(+), 7 deletions(-) |
| |
| --- a/arch/arm64/include/asm/pgtable-prot.h |
| +++ b/arch/arm64/include/asm/pgtable-prot.h |
| @@ -43,11 +43,11 @@ |
| #define PROT_DEFAULT (_PROT_DEFAULT | PTE_MAYBE_NG) |
| #define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_MAYBE_NG) |
| |
| -#define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE)) |
| -#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE)) |
| -#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC)) |
| -#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT)) |
| -#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL)) |
| +#define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE)) |
| +#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE)) |
| +#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC)) |
| +#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT)) |
| +#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL)) |
| |
| #define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE)) |
| #define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL)) |
| @@ -71,8 +71,9 @@ |
| #define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN) |
| |
| #define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN) |
| -#define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) |
| -#define PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE) |
| +/* shared+writable pages are clean by default, hence PTE_RDONLY|PTE_WRITE */ |
| +#define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) |
| +#define PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_WRITE) |
| #define PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN) |
| #define PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN) |
| #define PAGE_EXECONLY __pgprot(_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN) |