BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Muhammad Usama Anjum" <usama.anjum@arm.com>
Cc: dri-devel@lists.freedesktop.org, damon@lists.linux.dev,
	linux-perf-users@vger.kernel.org, bpf@vger.kernel.org
Subject: Re: [PATCH 4/9] mm: use hw_pte_t for generic PTE table storage
Date: Thu, 06 Aug 2026 09:00:43 +0000	[thread overview]
Message-ID: <20260806090044.CB9031F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260806083926.1807279-5-usama.anjum@arm.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [Critical] copy_present_ptes batches PTEs in shared mappings without FPB_RESPECT_WRITE, granting the child process unintended write access to read-only pages and bypassing filesystem write notification.
- [High] Page walk callbacks wp_pte() and clean_record_pte() access hardware bits on potentially non-present PTEs, risking metadata corruption.
--

--- Patch [4]: [PATCH 4/9] mm: use hw_pte_t for generic PTE table storage ---
commit 9f475c080b8384027672c2a2cfdb3246a47fd906
Author: Muhammad Usama Anjum <usama.anjum@arm.com>
Subject: mm: use hw_pte_t for generic PTE table storage

This commit converts generic page-table interfaces to use hw_pte_t pointers for
table storage instead of pte_t pointers. It retains pte_t for logical PTE
values, changing the vocabulary without altering representation or behavior.

> diff --git a/mm/mapping_dirty_helpers.c b/mm/mapping_dirty_helpers.c
> --- a/mm/mapping_dirty_helpers.c
> +++ b/mm/mapping_dirty_helpers.c
> @@ -31,7 +31,7 @@ struct wp_walk {
>   * The function write-protects a pte and records the range in
>   * virtual address space of touched ptes for efficient range TLB flushes.
>   */
> -static int wp_pte(pte_t *pte, unsigned long addr, unsigned long end,
> +static int wp_pte(hw_pte_t *pte, unsigned long addr, unsigned long end,
>  		  struct mm_walk *walk)
>  {
>  	struct wp_walk *wpwalk = walk->private;
>  	pte_t ptent = ptep_get(pte);
>  
>  	if (pte_write(ptent)) {

[Severity: High]
This isn't a bug introduced by this patch, but does this code modify hardware
bits on non-present PTEs?

The page walk callback wp_pte() processes all PTEs within a mapping range,
including non-present entries like migration or swap entries. It checks
pte_write() directly without verifying pte_present() first.

If a swap or migration entry overlaps with hardware writable bits, this check
might pass, causing pte_wrprotect() to be called. This can silently corrupt
swap or migration metadata, leading to memory corruption when the entry is
later resolved.

[ ... ]

> @@ -86,7 +86,7 @@ struct clean_walk {
>   * in the address_space, as well as the first and last of the bits
>   * touched.
>   */
> -static int clean_record_pte(pte_t *pte, unsigned long addr,
> +static int clean_record_pte(hw_pte_t *pte, unsigned long addr,
>  			    unsigned long end, struct mm_walk *walk)
>  {
>  	struct wp_walk *wpwalk = walk->private;
>  	struct clean_walk *cwalk = to_clean_walk(wpwalk);
>  	pte_t ptent = ptep_get(pte);
>  
>  	if (pte_dirty(ptent)) {

[Severity: High]
This is a pre-existing issue, but can this inadvertently corrupt non-present
PTEs?

Similar to wp_pte() above, clean_record_pte() evaluates pte_dirty() on the
entry without checking if the PTE is actually present. Calling present-PTE
accessors on non-present entries produces undefined results. If this evaluates
to true for a swap or migration entry, calling pte_mkclean() will overwrite
and corrupt the swap metadata.

[ ... ]

> diff --git a/mm/memory.c b/mm/memory.c
> --- a/mm/memory.c
> +++ b/mm/memory.c
[ ... ]
> @@ -1205,7 +1205,7 @@ static __always_inline void __copy_present_ptes(struct vm_area_struct *dst_vma,
>   */
>  static inline int
>  copy_present_ptes(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
> -		 pte_t *dst_pte, pte_t *src_pte, pte_t pte, unsigned long addr,
> +		 hw_pte_t *dst_pte, hw_pte_t *src_pte, pte_t pte, unsigned long addr,
>  		 int max_nr, int *rss, struct folio **prealloc)
>  {
>  	fpb_t flags = FPB_MERGE_WRITE;
>  	struct page *page;
>  	struct folio *folio;
>  	int err, nr;
>  
>  	page = vm_normal_page(src_vma, addr, pte);
>  	if (unlikely(!page))
>  		goto copy_pte;
>  
>  	folio = page_folio(page);
>  
>  	if (unlikely(!*prealloc && folio_test_large(folio) && max_nr != 1)) {
>  		if (!(src_vma->vm_flags & VM_SHARED))
>  			flags |= FPB_RESPECT_DIRTY;
>  		if (vma_soft_dirty_enabled(src_vma))
>  			flags |= FPB_RESPECT_SOFT_DIRTY;
>  
>  		nr = folio_pte_batch_flags(folio, src_vma, src_pte, &pte, max_nr, flags);

[Severity: Critical]
This is a pre-existing issue, but does this code allow read-only PTEs to become
writable in the child process?

In copy_present_ptes(), when batching PTEs for a shared mapping, the flags
variable includes FPB_MERGE_WRITE but the FPB_RESPECT_WRITE flag is missing.
This causes folio_pte_batch_flags() to group PTEs with differing write
permissions.

If a batch contains both writable and read-only PTEs (for example, a 4K page
was made writable via page_mkwrite() while the rest of the THP remains
read-only), FPB_MERGE_WRITE ensures the batched output PTE is marked writable.

For shared mappings, __copy_present_ptes() calls pte_mkclean() but does not
write-protect the PTE. Consequently, set_ptes() installs this clean but
writable PTE across the entire batched range in the child process.

When the child writes to these newly writable pages, the hardware sets the
dirty bit without a page fault. This bypasses the filesystem write
notifications, which can allow writes to unallocated blocks in sparse files
and silently drop data.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260806083926.1807279-1-usama.anjum@arm.com?part=4

  reply	other threads:[~2026-08-06  9:00 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-06  8:38 [PATCH 0/9] mm: distinguish PTE table storage from PTE values Muhammad Usama Anjum
2026-08-06  8:38 ` [PATCH 1/9] mm: introduce hw_pte_t for PTE table storage Muhammad Usama Anjum
2026-08-07  7:09   ` Alexander Gordeev
2026-08-06  8:38 ` [PATCH 2/9] mm: make hw_pte_t visible to generic PTE interfaces Muhammad Usama Anjum
2026-08-06  8:38 ` [PATCH 3/9] mm: name pointers to copied PTE values ptentp Muhammad Usama Anjum
2026-08-06  8:38 ` [PATCH 4/9] mm: use hw_pte_t for generic PTE table storage Muhammad Usama Anjum
2026-08-06  9:00   ` sashiko-bot [this message]
2026-08-06  8:38 ` [PATCH 5/9] mm: convert PTE table entries in ptep_get() Muhammad Usama Anjum
2026-08-06  8:57   ` sashiko-bot
2026-08-06  8:38 ` [PATCH 6/9] mm: convert PTE table entry to pte Muhammad Usama Anjum
2026-08-07  6:58   ` Alexander Gordeev
2026-08-06  8:38 ` [PATCH 7/9] mm/kasan: use hw_pte_t for the early shadow PTE table Muhammad Usama Anjum
2026-08-06  9:01   ` sashiko-bot
2026-08-06  8:38 ` [PATCH 8/9] drm/i915: use hw_pte_t for PTE range callbacks Muhammad Usama Anjum
2026-08-06  8:38 ` [PATCH 9/9] xen: " Muhammad Usama Anjum

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=20260806090044.CB9031F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=damon@lists.linux.dev \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=usama.anjum@arm.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