[PATCH] munmap sealed memory cause memory to split (bug)

From: jeffxu
Date: Wed Oct 16 2024 - 22:26:39 EST


From: Jeff Xu <jeffxu@xxxxxxxxxx>

It appears there is a regression on the latest mm,
when munmap sealed memory, it can cause unexpected VMA split.
E.g. repro use this test.
---
tools/testing/selftests/mm/mseal_test.c | 76 +++++++++++++++++++++++++
1 file changed, 76 insertions(+)

diff --git a/tools/testing/selftests/mm/mseal_test.c b/tools/testing/selftests/mm/mseal_test.c
index fa74dbe4a684..0af33e13b606 100644
--- a/tools/testing/selftests/mm/mseal_test.c
+++ b/tools/testing/selftests/mm/mseal_test.c
@@ -1969,6 +1969,79 @@ static void test_madvise_filebacked_was_writable(bool seal)
REPORT_TEST_PASS();
}

+static void test_munmap_free_multiple_ranges_with_split(bool seal)
+{
+ void *ptr;
+ unsigned long page_size = getpagesize();
+ unsigned long size = 12 * page_size;
+ int ret;
+ int prot;
+
+ setup_single_address(size, &ptr);
+ FAIL_TEST_IF_FALSE(ptr != (void *)-1);
+
+ /* seal the middle 4 page */
+ if (seal) {
+ ret = sys_mseal(ptr + 4 * page_size, 4 * page_size);
+ FAIL_TEST_IF_FALSE(!ret);
+
+ size = get_vma_size(ptr, &prot);
+ FAIL_TEST_IF_FALSE(size == 4 * page_size);
+ FAIL_TEST_IF_FALSE(prot == 4);
+
+ size = get_vma_size(ptr + 4 * page_size, &prot);
+ FAIL_TEST_IF_FALSE(size == 4 * page_size);
+ FAIL_TEST_IF_FALSE(prot == 4);
+
+ size = get_vma_size(ptr + 8 * page_size, &prot);
+ FAIL_TEST_IF_FALSE(size == 4 * page_size);
+ FAIL_TEST_IF_FALSE(prot == 4);
+ }
+
+ /* munmap 4 pages from the third page */
+ ret = sys_munmap(ptr + 2 * page_size, 4 * page_size);
+ if (seal) {
+ FAIL_TEST_IF_FALSE(ret);
+ FAIL_TEST_IF_FALSE(errno == EPERM);
+
+ size = get_vma_size(ptr, &prot);
+ FAIL_TEST_IF_FALSE(size == 4 * page_size);
+ FAIL_TEST_IF_FALSE(prot == 4);
+
+ size = get_vma_size(ptr + 4 * page_size, &prot);
+ FAIL_TEST_IF_FALSE(size == 4 * page_size);
+ FAIL_TEST_IF_FALSE(prot == 4);
+
+ size = get_vma_size(ptr + 8 * page_size, &prot);
+ FAIL_TEST_IF_FALSE(size == 4 * page_size);
+ FAIL_TEST_IF_FALSE(prot == 4);
+ } else
+ FAIL_TEST_IF_FALSE(!ret);
+
+ /* munmap 4 pages from the sealed page */
+ ret = sys_munmap(ptr + 6 * page_size, 4 * page_size);
+ if (seal) {
+ FAIL_TEST_IF_FALSE(ret);
+ FAIL_TEST_IF_FALSE(errno == EPERM);
+
+ size = get_vma_size(ptr + 4 * page_size, &prot);
+ FAIL_TEST_IF_FALSE(size == 4 * page_size);
+ FAIL_TEST_IF_FALSE(prot == 4);
+
+ size = get_vma_size(ptr + 4 * page_size, &prot);
+ FAIL_TEST_IF_FALSE(size == 4 * page_size);
+ FAIL_TEST_IF_FALSE(prot == 4);
+
+ size = get_vma_size(ptr + 8 * page_size, &prot);
+ FAIL_TEST_IF_FALSE(size == 4 * page_size);
+ FAIL_TEST_IF_FALSE(prot == 4);
+ } else
+ FAIL_TEST_IF_FALSE(!ret);
+
+ REPORT_TEST_PASS();
+}
+
+
int main(int argc, char **argv)
{
bool test_seal = seal_support();
@@ -2099,5 +2172,8 @@ int main(int argc, char **argv)
test_madvise_filebacked_was_writable(false);
test_madvise_filebacked_was_writable(true);

+ test_munmap_free_multiple_ranges_with_split(false);
+ test_munmap_free_multiple_ranges_with_split(true);
+
ksft_finished();
}
--
2.47.0.rc1.288.g06298d1525-goog