All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Kiryl Shutsemau" <kirill@shutemov.name>
Cc: kvm@vger.kernel.org
Subject: Re: [PATCH v7 14/15] selftests/mm: add userfaultfd RWP tests
Date: Mon, 29 Jun 2026 12:46:49 +0000	[thread overview]
Message-ID: <20260629124650.2978E1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260629120749.566063-15-kirill@shutemov.name>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Medium] Dereferencing a `void *` pointer causes a compilation error in selftests.
- [Medium] Impossible PAGEMAP_SCAN condition causes `rwp-mprotect` test to vacuously pass.
- [Medium] `rwp-mprotect` test will falsely pass if `mprotect()` completely strips the uffd-wp marker.
- [Medium] `rwp-fork-pin` test will falsely pass if the uffd-wp marker is not inherited by the child.
- [Low] Uninitialized stack memory read when PAGEMAP_SCAN returns 0 regions.
--

commit 636eb23e25c814d00a52fbe1a8d08dc386ad4472
Author: Kiryl Shutsemau (Meta) <kas@kernel.org>

selftests/mm: add userfaultfd RWP tests

This commit adds several tests for UFFDIO_REGISTER_MODE_RWP and
UFFDIO_RWPROTECT to the userfaultfd selftests. It covers async and sync
modes, PAGEMAP_SCAN, mprotect round-trips, GUP, and fork interactions.

> diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c
> index a6c14109e8188..8c49191835ea1 100644
> --- a/tools/testing/selftests/mm/uffd-unit-tests.c
> +++ b/tools/testing/selftests/mm/uffd-unit-tests.c
[ ... ]
> @@ -602,6 +617,687 @@ void uffd_minor_collapse_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *
[ ... ]
> +static void uffd_rwp_pagemap_test(uffd_global_test_opts_t *gopts,
> +					  uffd_test_args_t *args)
> +{
[ ... ]
> +	if (ret != 1 || regions[0].start != start ||
> +	    regions[0].end != boundary) {
> +		uffd_test_fail("hot set wrong: got %ld regions [0x%lx,0x%lx), expected 1 [0x%lx,0x%lx)",
> +			       ret, (unsigned long)regions[0].start,
> +			       (unsigned long)regions[0].end,
> +			       (unsigned long)start, (unsigned long)boundary);
> +		return;
> +	}

[Severity: Low]
Will this evaluate uninitialized array elements if PAGEMAP_SCAN returns 0?

The regions array is uninitialized, so if ret == 0, the kernel won't populate
regions[0]. The check ret != 1 is true, which leads to reading
regions[0].start and regions[0].end in the failure message, printing
undefined stack data.

> +
> +	uffd_test_pass();
> +}
[ ... ]
> +static void uffd_rwp_mprotect_test(uffd_global_test_opts_t *gopts,
> +				   uffd_test_args_t *args)
> +{
[ ... ]
> +	/* Round-trip mprotect(): PROT_NONE -> PROT_READ|PROT_WRITE */
> +	if (mprotect(gopts->area_dst, nr_pages * page_size, PROT_NONE))
> +		err("mprotect() PROT_NONE");
> +	if (mprotect(gopts->area_dst, nr_pages * page_size,
> +		     PROT_READ | PROT_WRITE))
> +		err("mprotect() PROT_READ|PROT_WRITE");
> +

[Severity: Medium]
Should the test verify the uffd-wp marker's presence immediately after the
mprotect round-trip, before touching the pages?

If a kernel bug causes mprotect to overwrite the PTE and clear the uffd-wp
marker completely, the subsequent memory access will succeed without a fault
and set the hardware accessed bit. A later scan for cold pages would still
find 0 pages, allowing the test to falsely pass.

> +	/* Touch every page. Async RWP must auto-resolve each fault. */
> +	for (p = 0; p < nr_pages; p++) {
> +		volatile char *page = gopts->area_dst + p * page_size;
> +		(void)*page;
> +	}
> +
> +	/*
> +	 * After touching, no page should remain RW-protected. A stuck
> +	 * uffd-wp bit would mean mprotect() silently dropped PROT_NONE and
> +	 * the access never faulted.
> +	 */
> +	pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
> +	if (pagemap_fd < 0)
> +		err("open pagemap");
> +
> +	memset(&pm_arg, 0, sizeof(pm_arg));
> +	pm_arg.size = sizeof(pm_arg);
> +	pm_arg.start = (uint64_t)gopts->area_dst;
> +	pm_arg.end = (uint64_t)gopts->area_dst + nr_pages * page_size;
> +	pm_arg.vec = (uint64_t)regions;
> +	pm_arg.vec_len = ARRAY_SIZE(regions);
> +	pm_arg.category_mask = PAGE_IS_ACCESSED;
> +	pm_arg.category_inverted = PAGE_IS_ACCESSED;

[Severity: Medium]
Does this create an impossible PAGEMAP_SCAN condition?

The test sets pm_arg.category_mask to PAGE_IS_ACCESSED, which requires the
bit to be set, but also sets pm_arg.category_inverted to PAGE_IS_ACCESSED,
requiring the bit to be clear.

This impossible condition will cause PAGEMAP_SCAN to always return 0 regions.
Since the test passes if ret == 0, it will silently pass regardless of the
actual page state, missing regressions.

> +	pm_arg.return_mask = PAGE_IS_ACCESSED;
> +
> +	ret = ioctl(pagemap_fd, PAGEMAP_SCAN, &pm_arg);
> +	close(pagemap_fd);
[ ... ]
> +static void uffd_rwp_fork_test(uffd_global_test_opts_t *gopts,
> +			       uffd_test_args_t *args)
> +{
> +	unsigned long nr_pages = gopts->nr_pages;
> +	unsigned long page_size = gopts->page_size;
> +	int pagemap_fd;
> +	uint64_t value;
> +
> +	if (uffd_register_rwp(gopts->uffd, gopts->area_dst,
> +			      nr_pages * page_size))
> +		err("register failed");
> +
> +	/* Populate + RWP-protect */
> +	*gopts->area_dst = 1;

[Severity: Medium]
Will this cause a compilation error?

The area_dst field in uffd_global_test_opts_t is a void pointer.
Dereferencing a void pointer directly violates C semantics and will cause an
invalid use of void expression error.

Should this be cast to char * or volatile char * first?

> +	rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
> +			page_size, true);
[ ... ]
> +static void uffd_rwp_fork_pin_test(uffd_global_test_opts_t *gopts,
> +				   uffd_test_args_t *args)
> +{
> +	unsigned long page_size = gopts->page_size;
> +	fork_event_args fevent_args = { .gopts = gopts, .child_uffd = -1 };
> +	pin_args pin_args = {};
> +	int pagemap_fd, status;
> +	pthread_t fevent_thread;
> +	uint64_t value;
> +	pid_t child;
> +
> +	if (uffd_register_rwp(gopts->uffd, gopts->area_dst, page_size))
> +		err("register failed");
> +
> +	/* Populate. */
> +	*gopts->area_dst = 1;

[Severity: Medium]
Will this also cause a compilation error due to dereferencing a void pointer,
similar to the instance in uffd_rwp_fork_test?

> +
> +	/* RO-longterm pin so fork() takes copy_present_page() for this PTE. */
> +	if (pin_pages(&pin_args, gopts->area_dst, page_size)) {
[ ... ]
> +	child = fork();
> +	if (child < 0)
> +		err("fork");
> +	if (child == 0) {
> +		volatile char c;
> +		int cfd;
> +
> +		/*
> +		 * Read the pinned page. Only reaches the fault path if the
> +		 * child PTE is protnone + uffd; async mode auto-resolves and
> +		 * clears the uffd bit. If copy_present_page() dropped
> +		 * PAGE_NONE, the read would silently succeed and the bit
> +		 * would still be set.
> +		 */
> +		c = *(volatile char *)gopts->area_dst;

[Severity: Medium]
Should the child assert that the PM_UFFD_WP bit is set before performing this
read?

If a kernel bug causes fork to fail to copy the uffd-wp marker to the child,
the read here will succeed without a fault, and the bit will already be
clear. The child will exit 0, and the test will falsely pass, masking a
potential regression in copy_present_page().

> +		(void)c;
> +
> +		cfd = pagemap_open();
> +		value = pagemap_get_entry(cfd, gopts->area_dst);
> +		close(cfd);
> +		_exit((value & PM_UFFD_WP) ? 1 : 0);
> +	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260629120749.566063-1-kirill@shutemov.name?part=14

  reply	other threads:[~2026-06-29 12:46 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-29 12:07 [PATCH v7 00/15] userfaultfd: working set tracking for VM guest memory Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 01/15] mm: decouple protnone helpers from CONFIG_NUMA_BALANCING Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 02/15] mm: rename uffd-wp PTE bit macros to uffd Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 03/15] mm: rename uffd-wp PTE accessors " Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 04/15] userfaultfd: test uffd VMA flags through the vma_flags_t API Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 05/15] mm: add VM_UFFD_RWP VMA flag Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 06/15] mm: add MM_CP_UFFD_RWP change_protection() flag Kiryl Shutsemau
2026-06-29 12:27   ` sashiko-bot
2026-06-29 12:07 ` [PATCH v7 07/15] mm: preserve RWP marker across PTE rewrites Kiryl Shutsemau
2026-06-29 12:33   ` sashiko-bot
2026-06-29 16:02     ` Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 08/15] mm: handle VM_UFFD_RWP in khugepaged, rmap, and GUP Kiryl Shutsemau
2026-06-29 12:50   ` sashiko-bot
2026-06-29 12:07 ` [PATCH v7 09/15] userfaultfd: add UFFDIO_REGISTER_MODE_RWP and UFFDIO_RWPROTECT plumbing Kiryl Shutsemau
2026-06-29 12:40   ` sashiko-bot
2026-06-29 12:07 ` [PATCH v7 10/15] mm/userfaultfd: add RWP fault delivery and expose UFFDIO_REGISTER_MODE_RWP Kiryl Shutsemau
2026-06-29 12:42   ` sashiko-bot
2026-06-29 12:07 ` [PATCH v7 11/15] mm/pagemap: add PAGE_IS_ACCESSED for RWP tracking Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 12/15] userfaultfd: add UFFD_FEATURE_RWP_ASYNC for async fault resolution Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 13/15] userfaultfd: add UFFDIO_SET_MODE for runtime sync/async toggle Kiryl Shutsemau
2026-06-29 12:07 ` [PATCH v7 14/15] selftests/mm: add userfaultfd RWP tests Kiryl Shutsemau
2026-06-29 12:46   ` sashiko-bot [this message]
2026-06-29 12:07 ` [PATCH v7 15/15] Documentation/userfaultfd: document RWP working set tracking Kiryl Shutsemau

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=20260629124650.2978E1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=kirill@shutemov.name \
    --cc=kvm@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.