From: "Carlos López" <clopez@suse.de>
To: kvm@vger.kernel.org, linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org, linux-s390@vger.kernel.org,
linux-riscv@lists.infradead.org, seanjc@google.com,
pbonzini@redhat.com, akpm@linux-foundation.org, david@kernel.org,
peterx@redhat.com, ljs@kernel.org, imbrenda@linux.ibm.com,
borntraeger@linux.ibm.com, frankja@linux.ibm.com,
"Carlos López" <clopez@suse.de>, "Zi Yan" <ziy@nvidia.com>,
"Baolin Wang" <baolin.wang@linux.alibaba.com>,
"Liam R. Howlett" <liam@infradead.org>,
"Nico Pache" <nico.pache@linux.dev>,
"Ryan Roberts" <ryan.roberts@arm.com>,
"Dev Jain" <dev.jain@arm.com>, "Barry Song" <baohua@kernel.org>,
"Lance Yang" <lance.yang@linux.dev>,
"Usama Arif" <usama.arif@linux.dev>,
"Kiryl Shutsemau" <kas@kernel.org>,
"Vlastimil Babka" <vbabka@kernel.org>,
"Mike Rapoport" <rppt@kernel.org>,
"Suren Baghdasaryan" <surenb@google.com>,
"Michal Hocko" <mhocko@suse.com>, "Jann Horn" <jannh@google.com>,
"Pedro Falcato" <pfalcato@suse.de>
Subject: [PATCH v2 5/9] mm/mprotect: keep writable entries writable on permission upgrades
Date: Thu, 5 Nov 2026 17:50:02 +0100 [thread overview]
Message-ID: <20261105165004.2663799-9-clopez@suse.de> (raw)
In-Reply-To: <20261105165004.2663799-4-clopez@suse.de>
change_protection() applies vma->vm_page_prot, which lacks the write bit
for CoW and write-notified mappings, so it write-protects every entry
in them. When an entry would simply be made writable on fault without
further checks (e.g. dirty PTEs in shared mappings, exclusive anonymous
pages), MM_CP_TRY_CHANGE_WRITABLE makes the entry writable again to
avoid the future fault.
However, writable entries in shared mappings that are not dirty still
become read-only. For example, a uffd-wp unprotect makes clean shmem
PTEs read-only even if they were never write-protected, e.g. when they
were mapped by a read fault before uffd-wp was registered. The next
write to each of them causes a fault that only restores the write bit.
Now that MM_CP_PERM_UPGRADE indicates whether mprotect() only adds
permissions, change_protection() can tell, together with the
userfaultfd unprotect flags, when a change revokes no access. Keep
writable entries writable in these cases, at the PTE, PMD and PUD
levels. This is consistent with the write fault handler, as an entry
that is already writable needs no write fault.
Signed-off-by: Carlos López <clopez@suse.de>
---
mm/huge_memory.c | 7 +++++++
mm/internal.h | 7 +++++++
mm/mprotect.c | 4 ++++
3 files changed, 18 insertions(+)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 506e1e61c0fd..6e23d0e4ae66 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2809,6 +2809,10 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
if (userfaultfd_rwp(vma) && pmd_uffd(entry))
entry = pmd_modify(entry, PAGE_NONE);
+ /* See change_present_ptes(). */
+ if (mm_cp_is_perm_upgrade(cp_flags) && pmd_write(oldpmd))
+ entry = pmd_mkwrite(entry, vma);
+
/* See change_pte_range(). */
if ((cp_flags & MM_CP_TRY_CHANGE_WRITABLE) && !pmd_write(entry) &&
can_change_pmd_writable(vma, addr, entry))
@@ -2885,6 +2889,9 @@ int change_huge_pud(struct mmu_gather *tlb, struct vm_area_struct *vma,
*/
oldpud = pudp_invalidate(vma, addr, pudp);
entry = pud_modify(oldpud, newprot);
+ /* See change_present_ptes(). */
+ if (mm_cp_is_perm_upgrade(cp_flags) && pud_write(oldpud))
+ entry = pud_mkwrite(entry);
/* See change_pte_range(). */
if ((cp_flags & MM_CP_TRY_CHANGE_WRITABLE) && !pud_write(entry) &&
can_change_pud_writable(vma, addr, entry))
diff --git a/mm/internal.h b/mm/internal.h
index 566cbd2dce48..a1a66f3b4b9c 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -1423,6 +1423,13 @@ static inline bool pte_needs_soft_dirty_wp(struct vm_area_struct *vma, pte_t pte
return vma_soft_dirty_enabled(vma) && !pte_soft_dirty(pte);
}
+/* Whether a change_protection() only adds permissions. */
+static inline bool mm_cp_is_perm_upgrade(unsigned long cp_flags)
+{
+ return cp_flags & (MM_CP_PERM_UPGRADE | MM_CP_UFFD_WP_RESOLVE |
+ MM_CP_UFFD_RWP_RESOLVE);
+}
+
/* shrinker related functions */
unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg,
int priority);
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 683131c9c4a0..16b8aef755ab 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -306,6 +306,10 @@ static __always_inline void change_present_ptes(struct mmu_gather *tlb,
if (userfaultfd_rwp(vma) && pte_uffd(ptent))
ptent = pte_modify(ptent, PAGE_NONE);
+ /* A permission upgrade keeps writable entries writable. */
+ if (mm_cp_is_perm_upgrade(cp_flags) && pte_write(oldpte))
+ ptent = pte_mkwrite(ptent, vma);
+
/*
* In some writable, shared mappings, we might want
* to catch actual write access -- see
--
2.51.0
next prev parent reply other threads:[~2026-11-05 17:01 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 16:49 [PATCH v2 0/9] KVM: don't zap secondary MMU on permission upgrade Carlos López
2026-11-05 16:49 ` [PATCH v2 1/9] mm: fix eager write-bit restore for write-notified shared mappings Carlos López
2026-11-05 16:49 ` [PATCH v2 2/9] riscv: mm: add pud_soft_dirty() Carlos López
2026-11-05 16:50 ` [PATCH v2 3/9] mm/huge_memory: honor MM_CP_TRY_CHANGE_WRITABLE in change_huge_pud() Carlos López
2026-11-05 16:50 ` [PATCH v2 4/9] mm/mprotect: add MM_CP_PERM_UPGRADE Carlos López
2026-11-05 16:50 ` Carlos López [this message]
2026-11-05 17:06 ` [PATCH v2 5/9] mm/mprotect: keep writable entries writable on permission upgrades David Hildenbrand (Arm)
2026-11-05 16:50 ` [PATCH v2 6/9] mm/mmu_notifier: add MMU_NOTIFIER_RANGE_PERM_UPGRADE Carlos López
2026-11-05 16:50 ` [PATCH v2 7/9] KVM: pass the mmu_notifier event and flags to kvm_gfn_range Carlos López
2026-11-05 16:50 ` [PATCH v2 8/9] KVM: x86/mmu: don't zap secondary MMU on permission upgrade Carlos López
2026-11-05 16:50 ` [PATCH v2 9/9] KVM: s390: don't unmap the gmap " Carlos López
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261105165004.2663799-9-clopez@suse.de \
--to=clopez@suse.de \
--cc=akpm@linux-foundation.org \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=borntraeger@linux.ibm.com \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=frankja@linux.ibm.com \
--cc=imbrenda@linux.ibm.com \
--cc=jannh@google.com \
--cc=kas@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=lance.yang@linux.dev \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-riscv@lists.infradead.org \
--cc=linux-s390@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=mhocko@suse.com \
--cc=nico.pache@linux.dev \
--cc=pbonzini@redhat.com \
--cc=peterx@redhat.com \
--cc=pfalcato@suse.de \
--cc=rppt@kernel.org \
--cc=ryan.roberts@arm.com \
--cc=seanjc@google.com \
--cc=surenb@google.com \
--cc=usama.arif@linux.dev \
--cc=vbabka@kernel.org \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®