On 09/01/2024 13:04, Chaitanya S Prakash wrote:
From: Chaitanya S Prakash chaitanyas.prakash@arm.com
When a capability is created it is assigned the maximum permissions it may ever have, by passing PROT_MAX(max_prot) as one of the prot flags. Any attempt to increase the permissions beyond this would result in failure of the syscall. An owning capability returned by mmap() does not include LoadCap and StoreCap permissions if the mapping is shared. A check to verify the same has been added.
mremap() doesn't take a prot argument and retains the permissions of the original capability. If the permissions of the new capability do not match the set of permissions of the old capabaility, the syscall fails with an -EINVAL error code.
Isn't that only true if the new set of permissions is larger than the old set?
[...]
- /* repeat positive max_prot test with fixed address */
- addr = (void *)(uintptr_t)(pagesize * 16);
It's not clear why a different value is used here compared to patch 7. It probably makes sense to define a constant shared between the tests.
- flags = MAP_PRIVATE | MAP_ANONYMOUS;
- max_prot = PROT_ALL;
- prot = PROT_READ | PROT_EXEC;
- ptr = mmap(addr, MMAP_SIZE, PROT_MAX(max_prot) | prot,
flags | MAP_FIXED, -1, 0);
- ASSERT_FALSE(IS_ERR_VALUE(ptr));
- retval = mprotect(ptr, MMAP_SIZE, PROT_WRITE);
- ASSERT_EQ(retval, 0);
- retval = munmap(ptr, MMAP_SIZE);
- ASSERT_EQ(retval, 0);
- /* LoadCap and StoreCap permissions must not be given to a shared mapping */
- flags = MAP_SHARED | MAP_ANONYMOUS;
- prot = PROT_READ | PROT_WRITE;
- ptr = mmap(NULL, MMAP_SIZE, PROT_MAX(prot) | PROT_READ, flags, -1, 0);
- ASSERT_FALSE(IS_ERR_VALUE(ptr));
- perms = cheri_perms_get(ptr);
- retval = ((perms & CHERI_PERM_LOAD) && (perms & CHERI_PERM_STORE_CAP));
I must have missed this in v4. Right now this checks that either Load or StoreCap is absent, which is probably not the point. I guess (perms & (CHERI_PERM_LOAD_CAP | CHERI_PERM_STORE_CAP))? That could be directly in the EXPECT_EQ().
- ASSERT_EQ(retval, 0);
- retval = munmap(ptr, MMAP_SIZE);
- ASSERT_EQ(retval, 0);
- /* permissions of capability returned by mremap must match the
* permissions returned by the original mapping
*/
- flags = MAP_PRIVATE | MAP_ANONYMOUS;
- prot = PROT_READ | PROT_WRITE;
- old_ptr = mmap(NULL, MMAP_SIZE_REDUCED, prot, flags, -1, 0);
- ASSERT_FALSE(IS_ERR_VALUE(old_ptr));
- old_perms = cheri_perms_get(old_ptr);
- new_ptr = mremap(old_ptr, MMAP_SIZE_REDUCED, MMAP_SIZE,
MREMAP_MAYMOVE, 0);
- ASSERT_FALSE(IS_ERR_VALUE(new_ptr));
- new_perms = cheri_perms_get(new_ptr);
- ASSERT_EQ(old_perms, new_perms);
old_ptr remains valid, so we can directly use cheri_perms_get() here without temporaries.
[...]