Overwriting part of a mapping within an existing reservation is allowed with the use of the MAP_FIXED flag. Whereas any attempt to write beyond the bounds of the existing reservation would cause the syscall to fail.
Address space management syscalls that manipulate a given mapping are restricted to the range owned by the capability. Any attempt to manage mappings beyond this range will result in failure of the syscall.
Signed-off-by: Chaitanya S Prakash chaitanyas.prakash@arm.com --- tools/testing/selftests/arm64/morello/mmap.c | 147 +++++++++++++++++++ 1 file changed, 147 insertions(+)
diff --git a/tools/testing/selftests/arm64/morello/mmap.c b/tools/testing/selftests/arm64/morello/mmap.c index 8a4cc40e6095..7b1a247719f4 100644 --- a/tools/testing/selftests/arm64/morello/mmap.c +++ b/tools/testing/selftests/arm64/morello/mmap.c @@ -248,6 +248,152 @@ TEST(test_validity_tag_check) ASSERT_EQ(retval, 0); }
+/* test to verify address space management syscall behaviour when capability + * range is modified + */ +TEST(test_range_check) +{ + void *ptr, *reduced_bound_ptr, *ret; + int retval; + int prot = PROT_READ | PROT_WRITE; + int flags = MAP_SHARED | MAP_ANONYMOUS; + unsigned char vec[MMAP_SIZE / pagesize]; + + /* mapping a smaller range at prev mmap ptr in a subsequent mmap() + * call without first unmapping + */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + ret = mmap(ptr, MMAP_SIZE_REDUCED, prot, flags | MAP_FIXED, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + EXPECT_EQ(0, probe_mem_range(ptr, MMAP_SIZE_REDUCED, + PROBE_MODE_TOUCH | PROBE_MODE_VERIFY)); + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* mapping a larger range at prev mmap ptr in a subsequent mmap() + * call without first unmapping + */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + ret = mmap(ptr, 2 * MMAP_SIZE, prot, flags | MAP_FIXED, -1, 0); + VERIFY_ERRNO((unsigned long)ret, (unsigned long)-EINVAL); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* negative munmap() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + reduced_bound_ptr = cheri_bounds_set(ptr, MMAP_SIZE_REDUCED); + retval = munmap(reduced_bound_ptr, MMAP_SIZE); + VERIFY_ERRNO(retval, -EINVAL); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* positive madvise() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + retval = madvise(ptr, MMAP_SIZE, MADV_WILLNEED); + ASSERT_EQ(retval, 0); + EXPECT_EQ(0, probe_mem_range(ptr, MMAP_SIZE, + PROBE_MODE_TOUCH | PROBE_MODE_VERIFY)); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* negative madvise() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + reduced_bound_ptr = cheri_bounds_set(ptr, MMAP_SIZE_REDUCED); + retval = madvise(reduced_bound_ptr, MMAP_SIZE, MADV_NORMAL); + VERIFY_ERRNO(retval, -EINVAL); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* positive mincore() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + retval = mincore(ptr, MMAP_SIZE, vec); + ASSERT_EQ(retval, 0); + EXPECT_EQ(0, probe_mem_range(ptr, MMAP_SIZE, + PROBE_MODE_TOUCH | PROBE_MODE_VERIFY)); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* negative mincore() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + reduced_bound_ptr = cheri_bounds_set(ptr, MMAP_SIZE_REDUCED); + retval = mincore(reduced_bound_ptr, MMAP_SIZE, vec); + VERIFY_ERRNO(retval, -EINVAL); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* positive mlock() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + retval = mlock(ptr, MMAP_SIZE); + EXPECT_EQ(0, probe_mem_range(ptr, MMAP_SIZE, + PROBE_MODE_TOUCH | PROBE_MODE_VERIFY)); + retval = munlock(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* negative mlock() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + reduced_bound_ptr = cheri_bounds_set(ptr, MMAP_SIZE_REDUCED); + retval = mlock(reduced_bound_ptr, MMAP_SIZE); + VERIFY_ERRNO(retval, -EINVAL); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* negative munlock() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + EXPECT_EQ(0, mlock2(ptr, MMAP_SIZE, MLOCK_ONFAULT)); + EXPECT_EQ(0, probe_mem_range(ptr, MMAP_SIZE, + PROBE_MODE_TOUCH | PROBE_MODE_VERIFY)); + reduced_bound_ptr = cheri_bounds_set(ptr, MMAP_SIZE_REDUCED); + retval = munlock(reduced_bound_ptr, MMAP_SIZE); + VERIFY_ERRNO(retval, -EINVAL); + + retval = munlock(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* positive msync() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + retval = msync(ptr, MMAP_SIZE, MS_SYNC); + ASSERT_EQ(retval, 0); + EXPECT_EQ(0, probe_mem_range(ptr, MMAP_SIZE, + PROBE_MODE_TOUCH | PROBE_MODE_VERIFY)); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); + + /* negative msync() range test */ + ptr = mmap(NULL, MMAP_SIZE, prot, flags, -1, 0); + ASSERT_FALSE(IS_ERR_VALUE(ptr)); + reduced_bound_ptr = cheri_bounds_set(ptr, MMAP_SIZE_REDUCED); + retval = msync(reduced_bound_ptr, MMAP_SIZE, MS_SYNC); + VERIFY_ERRNO(retval, -EINVAL); + + retval = munmap(ptr, MMAP_SIZE); + ASSERT_EQ(retval, 0); +} + int main(int argc, char **argv, char **envp, struct morello_auxv *auxv) { reg_data.argc = argc; @@ -261,5 +407,6 @@ int main(int argc, char **argv, char **envp, struct morello_auxv *auxv) test_syscall_mmap2(); test_map_growsdown(); test_validity_tag_check(); + test_range_check(); return 0; }