Helper functions such as capability_owns_range(), build_owning_capability() and mapping_to_capability_perm() are added to manage capability constraints as per PCuABI specifications.
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 amitdaniel.kachhap@arm.com --- include/linux/cap_addr_mgmt.h | 52 +++++++++++++++++++++++++++++++++++ mm/cap_addr_mgmt.c | 36 +++++++++++++++++++++++- 2 files changed, 87 insertions(+), 1 deletion(-)
diff --git a/include/linux/cap_addr_mgmt.h b/include/linux/cap_addr_mgmt.h index 2f296f02c3ff..6a42e714ecd5 100644 --- a/include/linux/cap_addr_mgmt.h +++ b/include/linux/cap_addr_mgmt.h @@ -143,6 +143,38 @@ static inline void reserv_fork(struct mm_struct *mm, struct mm_struct *oldmm) set_bit(MMF_PCUABI_RESERVE, &mm->flags); }
+/** + * 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, ptraddr_t addr, size_t len); + +/** + * build_owning_capability() - Creates a userspace capability from the + * requested base address, length and memory permission flags. + * @addr: Requested capability address. + * @len: Requested capability length. + * @perm: Requested capability permission flags. + * + * Return: A new capability derived from cheri_user_root_cap. + */ +user_uintptr_t build_owning_capability(ptraddr_t addr, size_t len, cheri_perms_t perm); + +/** + * mapping_to_capability_perm() - Converts memory mapping protection flags to + * capability permission flags. + * @prot: Memory protection flags. + * @has_tag_access: Capability permissions to have tag check flags. + * + * Return: Capability permission flags + */ +cheri_perms_t mapping_to_capability_perm(int prot, bool has_tag_access); + #else /* CONFIG_CHERI_PURECAP_UABI */
static inline int reserv_vma_set_reserv(struct vm_area_struct *vma, ptraddr_t start, @@ -191,6 +223,26 @@ static inline bool reserv_vma_is_supported(struct vm_area_struct *vma)
static inline void reserv_fork(struct mm_struct *mm, struct mm_struct *oldmm) {}
+static inline bool capability_owns_range(user_uintptr_t cap, ptraddr_t addr, size_t len) +{ + return true; +} + +static inline user_uintptr_t build_owning_capability(ptraddr_t addr, size_t len, cheri_perms_t perm) +{ + return addr; +} + +static inline bool capability_may_set_prot(user_uintptr_t cap, int prot) +{ + return true; +} + +static inline cheri_perms_t mapping_to_capability_perm(int prot, bool has_tag_access) +{ + return 0; +} + #endif /* CONFIG_CHERI_PURECAP_UABI */
#endif /* _LINUX_CAP_ADDR_MGMT_H */ diff --git a/mm/cap_addr_mgmt.c b/mm/cap_addr_mgmt.c index 8b5f98d0d01c..0112b2136755 100644 --- a/mm/cap_addr_mgmt.c +++ b/mm/cap_addr_mgmt.c @@ -59,7 +59,7 @@ user_uintptr_t reserv_range_set_reserv(ptraddr_t start, size_t len, cheri_perms_ } if (!locked) mmap_write_unlock(current->mm); - ret = (user_uintptr_t)uaddr_to_user_ptr_safe(start); + ret = build_owning_capability(start, len, perm);
return ret; } @@ -173,4 +173,38 @@ bool reserv_vma_is_supported(struct vm_area_struct *vma) return false; }
+bool capability_owns_range(user_uintptr_t cap, ptraddr_t addr, size_t len) +{ + ptraddr_t align_addr = round_down(addr, PAGE_SIZE); + size_t align_len = round_up(len, PAGE_SIZE); + + if (!test_bit(MMF_PCUABI_RESERVE, ¤t->mm->flags)) + 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(ptraddr_t addr, size_t len, cheri_perms_t perm) +{ + ptraddr_t align_start = CHERI_REPRESENTABLE_BASE(round_down(addr, PAGE_SIZE), len); + size_t align_len = cheri_representable_length(round_up(len, PAGE_SIZE)); + user_uintptr_t ret; + + if (!test_bit(MMF_PCUABI_RESERVE, ¤t->mm->flags)) + return (user_uintptr_t)addr; + + ret = (user_uintptr_t)cheri_build_user_cap(align_start, align_len, perm); + + return cheri_address_set(ret, addr); +} + +cheri_perms_t mapping_to_capability_perm(int prot __maybe_unused, + bool has_tag_access __maybe_unused) +{ + /* TODO [PCuABI] - capability permission conversion from memory permission */ + return (CHERI_PERMS_READ | CHERI_PERMS_WRITE | + CHERI_PERMS_EXEC | CHERI_PERMS_ROOTCAP); +} + #endif /* CONFIG_CHERI_PURECAP_UABI */