From: Chaitanya S Prakash chaitanyas.prakash@arm.com
Attempting to remap a range larger than what is owned by the capability triggers a -EINVAL error. Additionally, mappings that have to be moved in order to satisfy the new constraints, expect the MREMAP_MAYMOVE flag to be specified. Failure to do so triggers the -ENOMEM error. Within the bounds of a reservation, mremap() can be used to grow the mappings in-place. Tests to verify this behaviour have been added.
Signed-off-by: Chaitanya S Prakash chaitanyas.prakash@arm.com --- tools/testing/selftests/arm64/morello/mmap.c | 57 ++++++++++++++++++++ 1 file changed, 57 insertions(+)
diff --git a/tools/testing/selftests/arm64/morello/mmap.c b/tools/testing/selftests/arm64/morello/mmap.c index 727937b49c11..610ba12a35ff 100644 --- a/tools/testing/selftests/arm64/morello/mmap.c +++ b/tools/testing/selftests/arm64/morello/mmap.c @@ -343,6 +343,62 @@ TEST(test_mmap_bounds_check) ASSERT_EQ(retval, 0); }
+/* test to verify mremap() behaviour when capability bounds are modified */ +TEST(test_mremap_bounds_check) +{ + void *addr, *ptr, *new_ptr; + int retval; + int prot = PROT_READ | PROT_WRITE; + int flags = MAP_PRIVATE | MAP_ANONYMOUS; + + /* moving a mapping with MREMAP_MAYMOVE flag specified */ + ptr = mmap(NULL, MMAP_SIZE_REDUCED, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + + new_ptr = mremap(ptr, MMAP_SIZE_REDUCED, MMAP_SIZE, MREMAP_MAYMOVE, NULL); + ASSERT_FALSE(IS_ERR_VALUE(new_ptr)); + ASSERT_NE((unsigned long)ptr, (unsigned long)new_ptr); + EXPECT_EQ(0, probe_mem_range(new_ptr, MMAP_SIZE, + PROBE_MODE_TOUCH | PROBE_MODE_VERIFY)); + + retval = munmap(new_ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* moving a mapping without MREMAP_MAYMOVE flag triggers an ENOMEM error */ + ptr = mmap(NULL, MMAP_SIZE_REDUCED, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + + new_ptr = mremap(ptr, MMAP_SIZE_REDUCED, MMAP_SIZE, 0, 0); + EXPECT_EQ((unsigned long)new_ptr, (unsigned long)-ENOMEM); + + retval = munmap(ptr, MMAP_SIZE_REDUCED); + ASSERT_EQ(retval, 0); + + /* attempt to resize a mapping range greater than what the capability owns */ + ptr = mmap(NULL, MMAP_SIZE_REDUCED, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + + new_ptr = mremap(ptr, MMAP_SIZE, MMAP_SIZE, MREMAP_MAYMOVE, 0); + EXPECT_EQ((unsigned long)new_ptr, (unsigned long)-EINVAL); + + retval = munmap(ptr, MMAP_SIZE_REDUCED); + ASSERT_EQ(retval, 0); + + /* attempt to grow mappings in-place */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + + addr = (void *)(uintptr_t)(ptr + MMAP_SIZE_REDUCED); + retval = munmap(addr, MMAP_SIZE_REDUCED); + ASSERT_EQ(retval, 0); + + new_ptr = mremap(ptr, MMAP_SIZE_REDUCED, MMAP_SIZE, 0, 0); + ASSERT_FALSE(IS_ERR_VALUE(new_ptr)); + + retval = munmap(new_ptr, MMAP_SIZE); + EXPECT_EQ(retval, 0); +} + int main(__unused int argc, __unused char **argv, __unused char **envp, struct morello_auxv *auxv) { pagesize = get_pagesize(auxv); @@ -353,5 +409,6 @@ int main(__unused int argc, __unused char **argv, __unused char **envp, struct m test_validity_tag_check(); test_range_check(); test_mmap_bounds_check(); + test_mremap_bounds_check(); return 0; }