Helper functions such as capability_owns_range() and build_owning_capability() are added as per PCuABI specifications.
These may be helpful in adding different PCuABI reservation constraints.
Note: These helper functions do not check for capability permission constraints and full support will be added in subsequent commits.
Signed-off-by: Amit Daniel Kachhap amit.kachhap@arm.com --- include/linux/cap_addr_mgmt.h | 22 +++++++++++++++++++++ mm/cap_addr_mgmt.c | 37 ++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/include/linux/cap_addr_mgmt.h b/include/linux/cap_addr_mgmt.h index 00eda91c2fc0..60af5633ef6f 100644 --- a/include/linux/cap_addr_mgmt.h +++ b/include/linux/cap_addr_mgmt.h @@ -113,4 +113,26 @@ bool reserv_vma_match_capability(struct vm_area_struct *vma, user_uintptr_t star * Return: True if two vma's have the same reservation range or false otherwise. */ bool reserv_vma_match_properties(struct vm_area_struct *vma1, struct vm_area_struct *vma2); + +/** + * capability_owns_range() - Check if the address range is within the valid + * capability bound. + * @cap: A Capability value. + * @addr: Address start value. + * @len: Address length. + * + * Return: True if address within the capability bound or false otherwise. + */ +bool capability_owns_range(user_uintptr_t cap, unsigned long addr, unsigned long len); + +/** + * build_owning_capability() - Creates a userspace capability from the + * requested base address, length and memory protection flags. + * @addr: Requested capability address. + * @len: Requested capability length. + * @perm: Requested memory mapping permission flags. + * + * Return: A new capability derived from cheri_user_root_cap. + */ +user_uintptr_t build_owning_capability(unsigned long addr, unsigned long len, unsigned long perm); #endif /* _LINUX_CAP_ADDR_MGMT_H */ diff --git a/mm/cap_addr_mgmt.c b/mm/cap_addr_mgmt.c index fe318c92dc7a..a4a85b37d59d 100644 --- a/mm/cap_addr_mgmt.c +++ b/mm/cap_addr_mgmt.c @@ -77,7 +77,7 @@ user_uintptr_t reserv_range_insert_entry(unsigned long start, unsigned long len, WRITE_ONCE(vma->reserv_perm, cheri_perm); } mmap_write_unlock(current->mm); - ret = (user_uintptr_t)uaddr_to_user_ptr_safe(start); + ret = build_owning_capability(start, len, perm);
return ret; } @@ -178,6 +178,31 @@ bool reserv_vma_match_properties(struct vm_area_struct *vma1, struct vm_area_str return false; }
+bool capability_owns_range(user_uintptr_t cap, unsigned long addr, unsigned long len) +{ + unsigned long align_addr = round_down(addr, PAGE_SIZE); + unsigned long align_len = cheri_representable_length(round_up(len, PAGE_SIZE)); + + if (is_compat_task()) + return true; + + return cheri_check_cap((const void * __capability)cheri_address_set(cap, align_addr), + align_len, CHERI_PERM_GLOBAL | CHERI_PERM_SW_VMEM); +} + +user_uintptr_t build_owning_capability(unsigned long addr, unsigned long len, + unsigned long perm __maybe_unused) +{ + unsigned long align_start = round_down(addr, PAGE_SIZE); + unsigned long align_len = cheri_representable_length(round_up(len, PAGE_SIZE)); + + /* TODO [PCuABI] - capability permission conversion from memory permission */ + cheri_perms_t perms = CHERI_PERMS_READ | CHERI_PERMS_WRITE | + CHERI_PERMS_EXEC | CHERI_PERMS_ROOTCAP; + + return (user_uintptr_t)cheri_build_user_cap(align_start, align_len, perms); +} + #else
int reserv_vma_insert_entry(struct vm_area_struct *vma, unsigned long start, @@ -219,4 +244,14 @@ bool reserv_vma_match_properties(struct vm_area_struct *vma1, struct vm_area_str return true; }
+bool capability_owns_range(user_uintptr_t cap, unsigned long addr, unsigned long len) +{ + return true; +} + +user_uintptr_t build_owning_capability(unsigned long addr, unsigned long len, unsigned long perm) +{ + return addr; +} + #endif /* CONFIG_CHERI_PURECAP_UABI */