Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Sarthak Sharma <sarthak.sharma@arm.com>
To: Andrew Morton <akpm@linux-foundation.org>,
	David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>,
	"Liam R . Howlett" <liam@infradead.org>,
	Vlastimil Babka <vbabka@kernel.org>,
	Mike Rapoport <rppt@kernel.org>,
	Suren Baghdasaryan <surenb@google.com>,
	Michal Hocko <mhocko@suse.com>, Shuah Khan <shuah@kernel.org>,
	John Hubbard <jhubbard@nvidia.com>,
	Kalesh Singh <kaleshsingh@google.com>,
	Anshuman Khandual <anshuman.khandual@arm.com>,
	Park Tae-sun <ts930@dgu.ac.kr>,
	linux-mm@kvack.org, linux-kselftest@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Sarthak Sharma <sarthak.sharma@arm.com>
Subject: [PATCH RESEND 9/9] selftests/mm: mremap_test: strengthen multi VMA validation
Date: Thu, 24 Sep 2026 10:30:09 +0530	[thread overview]
Message-ID: <20260924050009.19974-10-sarthak.sharma@arm.com> (raw)
In-Reply-To: <20260924050009.19974-1-sarthak.sharma@arm.com>

Tests in mremap_test.c where a multi VMA range is involved only
check if the data remains consistent across mapped pages after
remap. They do not verify the mapping state of gaps in the
remapped range.

Add helpers to check whether a range is mapped with the
expected permissions using /proc/self/maps. Use them to
verify that gaps remain unmapped after regular remaps and
retain PROT_NONE permissions when remapping over an
existing mapping with PROT_NONE permissions.

Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 91 +++++++++++++++++++-----
 1 file changed, 72 insertions(+), 19 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 77e952556be1..1d9934b9a60b 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -124,13 +124,15 @@ static unsigned long long get_mmap_min_addr(void)
 }
 
 /*
- * Using /proc/self/maps, assert that the specified address range is contained
- * within a single mapping.
+ * Using /proc/self/maps, check whether the specified address range is contained
+ * within a single mapping with the expected permissions, if supplied.
  */
-static bool is_range_mapped(FILE *maps_fp, unsigned long start,
-			    unsigned long end)
+static bool is_range_mapped_with_perms(FILE *maps_fp, unsigned long start,
+				       unsigned long end,
+				       const char *expected_perms)
 {
 	char *line = NULL;
+	char perms[5];
 	size_t len = 0;
 	bool success = false;
 	unsigned long first_val, second_val;
@@ -138,12 +140,13 @@ static bool is_range_mapped(FILE *maps_fp, unsigned long start,
 	rewind(maps_fp);
 
 	while (getline(&line, &len, maps_fp) != -1) {
-		if (sscanf(line, "%lx-%lx", &first_val, &second_val) != 2) {
+		if (sscanf(line, "%lx-%lx %4s", &first_val, &second_val, perms) != 3) {
 			ksft_exit_fail_msg("cannot parse /proc/self/maps\n");
 			break;
 		}
 
-		if (first_val <= start && second_val >= end) {
+		if (first_val <= start && second_val >= end &&
+		    (!expected_perms || !strcmp(perms, expected_perms))) {
 			success = true;
 			fflush(maps_fp);
 			break;
@@ -154,6 +157,12 @@ static bool is_range_mapped(FILE *maps_fp, unsigned long start,
 	return success;
 }
 
+static bool is_range_mapped(FILE *maps_fp, unsigned long start,
+			    unsigned long end)
+{
+	return is_range_mapped_with_perms(maps_fp, start, end, NULL);
+}
+
 /* Check if [ptr, ptr + size) mapped in /proc/self/maps. */
 static bool is_ptr_mapped(FILE *maps_fp, void *ptr, unsigned long size)
 {
@@ -163,6 +172,20 @@ static bool is_ptr_mapped(FILE *maps_fp, void *ptr, unsigned long size)
 	return is_range_mapped(maps_fp, start, end);
 }
 
+/*
+ * Check if [ptr, ptr + size) is mapped with the required permissions in
+ * /proc/self/maps.
+ */
+static bool is_ptr_mapped_with_perms(FILE *maps_fp, void *ptr,
+				     unsigned long size,
+				     const char *expected_perms)
+{
+	unsigned long start = (unsigned long)ptr;
+	unsigned long end = start + size;
+
+	return is_range_mapped_with_perms(maps_fp, start, end, expected_perms);
+}
+
 /*
  * Returns the start address of the mapping on success, else returns
  * NULL on failure.
@@ -351,16 +374,37 @@ static void mremap_move_within_range(void)
 	ksft_test_result(success, "%s\n", test_name);
 }
 
-static bool is_multiple_vma_range_ok(char *ptr, unsigned long page_size)
+static bool is_multiple_vma_range_ok(FILE *maps_fp, char *ptr,
+				     unsigned long page_size, bool expect_gaps_mapped)
 {
 	int i;
 
-	for (i = 0; i <= 10; i += 2) {
+	for (i = 0; i <= 10; i++) {
 		size_t size = i == 4 ? 3 * page_size : page_size;
 
-		if (i == 6)
+		/* Pages 4, 5 and 6 are part of the same VMA. */
+		if (i == 5 || i == 6)
 			continue;
 
+		/* Odd pages correspond to gaps between the source VMAs. */
+		if (i & 1) {
+			if (expect_gaps_mapped) {
+				if (!is_ptr_mapped_with_perms(maps_fp,
+							      ptr + i * page_size,
+							      page_size, "---p")) {
+					ksft_print_msg("Page %d PROT_NONE mapping overwritten\n",
+						       i);
+					return false;
+				}
+			} else if (is_ptr_mapped(maps_fp, ptr + i * page_size,
+						 page_size)) {
+				ksft_print_msg("Page %d is unexpectedly mapped\n", i);
+				return false;
+			}
+
+			continue;
+		}
+
 		if (memcmp(ptr + i * page_size, (char *)pattern + i * page_size,
 			   size)) {
 			ksft_print_msg("Data in VMA starting at page %d got corrupted\n",
@@ -371,7 +415,8 @@ static bool is_multiple_vma_range_ok(char *ptr, unsigned long page_size)
 	return true;
 }
 
-static void mremap_move_multiple_vmas(unsigned long page_size, bool dont_unmap)
+static void mremap_move_multiple_vmas(FILE *maps_fp, unsigned long page_size,
+				      bool dont_unmap)
 {
 	int mremap_flags = MREMAP_FIXED | MREMAP_MAYMOVE;
 	char *test_name = "mremap move multiple vmas";
@@ -432,7 +477,7 @@ static void mremap_move_multiple_vmas(unsigned long page_size, bool dont_unmap)
 		goto out_unmap;
 	}
 	/* Check move was ok. */
-	if (!is_multiple_vma_range_ok(tgt_ptr, page_size)) {
+	if (!is_multiple_vma_range_ok(maps_fp, tgt_ptr, page_size, false)) {
 		success = false;
 		goto out_unmap;
 	}
@@ -445,7 +490,7 @@ static void mremap_move_multiple_vmas(unsigned long page_size, bool dont_unmap)
 		goto out_unmap;
 	}
 	/* Check that the move is ok. */
-	if (!is_multiple_vma_range_ok(&tgt_ptr[size], page_size)) {
+	if (!is_multiple_vma_range_ok(maps_fp, &tgt_ptr[size], page_size, false)) {
 		success = false;
 		goto out_unmap;
 	}
@@ -465,7 +510,7 @@ static void mremap_move_multiple_vmas(unsigned long page_size, bool dont_unmap)
 		goto out_unmap;
 	}
 	/* Check that the move is ok. */
-	if (!is_multiple_vma_range_ok(tgt_ptr, page_size)) {
+	if (!is_multiple_vma_range_ok(maps_fp, tgt_ptr, page_size, true)) {
 		success = false;
 		goto out_unmap;
 	}
@@ -554,7 +599,8 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 	ksft_test_result(success, "%s%s\n", test_name, inplace ? " [inplace]" : "");
 }
 
-static void mremap_move_multiple_vmas_split(unsigned long page_size,
+static void mremap_move_multiple_vmas_split(FILE *maps_fp,
+					    unsigned long page_size,
 					    bool dont_unmap)
 {
 	char *test_name = "mremap move multiple vmas split";
@@ -629,8 +675,15 @@ static void mremap_move_multiple_vmas_split(unsigned long page_size,
 
 	/* Check pattern. */
 	for (i = 0; i < 7; i++) {
-		if (i == 3)
+		if (i == 3) {
+			if (is_ptr_mapped(maps_fp, tgt_ptr + i * page_size,
+					  page_size)) {
+				ksft_print_msg("Page %d is unexpectedly mapped\n", i);
+				success = false;
+				goto out_unmap;
+			}
 			continue;
+		}
 
 		if (memcmp(tgt_ptr + i * page_size,
 			   (char *)pattern + (i + 2) * page_size, page_size)) {
@@ -1177,10 +1230,10 @@ int main(void)
 	mremap_move_1mb_from_start();
 	mremap_shrink_multiple_vmas(page_size, /* inplace= */true);
 	mremap_shrink_multiple_vmas(page_size, /* inplace= */false);
-	mremap_move_multiple_vmas(page_size, /* dontunmap= */ false);
-	mremap_move_multiple_vmas(page_size, /* dontunmap= */ true);
-	mremap_move_multiple_vmas_split(page_size, /* dontunmap= */ false);
-	mremap_move_multiple_vmas_split(page_size, /* dontunmap= */ true);
+	mremap_move_multiple_vmas(maps_fp, page_size, /* dontunmap= */ false);
+	mremap_move_multiple_vmas(maps_fp, page_size, /* dontunmap= */ true);
+	mremap_move_multiple_vmas_split(maps_fp, page_size, /* dontunmap= */ false);
+	mremap_move_multiple_vmas_split(maps_fp, page_size, /* dontunmap= */ true);
 	mremap_move_multi_invalid_vmas(maps_fp, page_size);
 
 	fclose(maps_fp);
-- 
2.53.0



  parent reply	other threads:[~2026-09-24  5:01 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-24  5:00 [PATCH RESEND 0/9] selftests/mm: improve mremap_test Sarthak Sharma
2026-09-24  5:00 ` [PATCH RESEND 1/9] selftests/mm: mremap_test: use kselftest helpers Sarthak Sharma
2026-09-29  7:58   ` David Hildenbrand (Arm)
2026-09-29  9:12     ` Sarthak Sharma
2026-09-24  5:00 ` [PATCH RESEND 2/9] selftests/mm: mremap_test: skip test when userfaultfd is unavailable Sarthak Sharma
2026-09-29  8:00   ` David Hildenbrand (Arm)
2026-09-29  9:17     ` Sarthak Sharma
2026-09-24  5:00 ` [PATCH RESEND 3/9] selftests/mm: mremap_test: fail unexpected mremap successes Sarthak Sharma
2026-09-29  8:17   ` David Hildenbrand (Arm)
2026-09-24  5:00 ` [PATCH RESEND 4/9] selftests/mm: mremap_test: correct multiple VMA range size Sarthak Sharma
2026-10-01 11:54   ` David Hildenbrand (Arm)
2026-10-01 12:42     ` Sarthak Sharma
2026-09-24  5:00 ` [PATCH RESEND 5/9] selftests/mm: mremap_test: fail on data corruption Sarthak Sharma
2026-10-01 11:54   ` David Hildenbrand (Arm)
2026-09-24  5:00 ` [PATCH RESEND 6/9] selftests/mm: mremap_test: replace random data with deterministic pattern Sarthak Sharma
2026-10-01 12:00   ` David Hildenbrand (Arm)
2026-10-01 13:16     ` Sarthak Sharma
2026-10-01 13:19       ` David Hildenbrand (Arm)
2026-09-24  5:00 ` [PATCH RESEND 7/9] selftests/mm: mremap_test: remove perf tests and timing Sarthak Sharma
2026-10-01 11:56   ` David Hildenbrand (Arm)
2026-09-24  5:00 ` [PATCH RESEND 8/9] selftests/mm: mremap_test: remove validation threshold Sarthak Sharma
2026-09-24  5:00 ` Sarthak Sharma [this message]
2026-09-29  5:54 ` [PATCH RESEND 0/9] selftests/mm: improve mremap_test Sarthak Sharma
2026-09-29  7:32   ` Kalesh Singh
2026-09-29  7:47     ` David Hildenbrand (Arm)
2026-09-29  9:05       ` Sarthak Sharma
2026-09-29  8:36 ` Lorenzo Stoakes (ARM)

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=20260924050009.19974-10-sarthak.sharma@arm.com \
    --to=sarthak.sharma@arm.com \
    --cc=akpm@linux-foundation.org \
    --cc=anshuman.khandual@arm.com \
    --cc=david@kernel.org \
    --cc=jhubbard@nvidia.com \
    --cc=kaleshsingh@google.com \
    --cc=liam@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=mhocko@suse.com \
    --cc=rppt@kernel.org \
    --cc=shuah@kernel.org \
    --cc=surenb@google.com \
    --cc=ts930@dgu.ac.kr \
    --cc=vbabka@kernel.org \
    /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