Helper functions user_ptr_may_set_prot() and user_ptr_owning_perms_from_prot() are added/modified to manage capability permissions in memory management syscalls as per PCuABI specifications.
Also, use arch-specific hook arch_user_ptr_owning_perms_from_prot() to convert arch-specific mapping protection to capability permissions.
Signed-off-by: Amit Daniel Kachhap amitdaniel.kachhap@arm.com --- Documentation/core-api/user_ptr.rst | 1 + arch/Kconfig | 3 ++ include/linux/user_ptr.h | 16 +++++++++ lib/user_ptr.c | 50 +++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/Documentation/core-api/user_ptr.rst b/Documentation/core-api/user_ptr.rst index 0ad6e14e14c4..4d7188792a13 100644 --- a/Documentation/core-api/user_ptr.rst +++ b/Documentation/core-api/user_ptr.rst @@ -358,5 +358,6 @@ APIs consider those requirements while creating and checking user pointers. * ``check_user_ptr_owning(ptr, addr, n)`` * ``make_user_ptr_owning(addr, n, perm)`` * ``user_ptr_owning_perms_from_prot(prot, tag_perm)`` +* ``user_ptr_may_set_prot(ptr, prot)``
See ``<linux/user_ptr.h>`` for details on how to use them. diff --git a/arch/Kconfig b/arch/Kconfig index 19f7bbb20a41..161f7002b0ab 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1502,6 +1502,9 @@ config CHERI_PURECAP_UABI availability of CHERI capabilities at compile-time; the resulting kernel image will not boot on incompatible hardware.
+config HAVE_ARCH_USER_PTR_H + bool + source "kernel/gcov/Kconfig"
source "scripts/gcc-plugins/Kconfig" diff --git a/include/linux/user_ptr.h b/include/linux/user_ptr.h index 41ab156653c7..ffb55e67f704 100644 --- a/include/linux/user_ptr.h +++ b/include/linux/user_ptr.h @@ -142,6 +142,17 @@ user_uintptr_t make_user_ptr_owning(ptraddr_t addr, size_t len, user_ptr_perms_t */ user_ptr_perms_t user_ptr_owning_perms_from_prot(int prot, bool has_tag_access);
+/** + * user_ptr_may_set_prot() - Verify if the mapping protection flags confirms + * with the capability permission flags. + * @user_ptr: User pointer. + * @prot: Memory protection flag. + * + * Return: True if the capability permissions includes the protection flags + * or false otherwise. + */ +bool user_ptr_may_set_prot(user_uintptr_t user_ptr, int prot); + #else /* CONFIG_CHERI_PURECAP_UABI */
typedef int user_ptr_perms_t; @@ -197,6 +208,11 @@ static inline user_ptr_perms_t user_ptr_owning_perms_from_prot(int prot, bool ha return 0; }
+static inline bool user_ptr_may_set_prot(user_uintptr_t user_ptr, int prot) +{ + return true; +} + #endif /* CONFIG_CHERI_PURECAP_UABI */
/** diff --git a/lib/user_ptr.c b/lib/user_ptr.c index 2ef58193fdad..a96866143349 100644 --- a/lib/user_ptr.c +++ b/lib/user_ptr.c @@ -2,9 +2,14 @@ #include <linux/bug.h> #include <linux/cap_addr_mgmt.h> #include <linux/cheri.h> +#include <linux/mman.h> #include <linux/sched.h> #include <linux/user_ptr.h>
+#ifdef CONFIG_HAVE_ARCH_USER_PTR_H +#include <asm/user_ptr.h> +#endif + void __user *uaddr_to_user_ptr(ptraddr_t addr) { /* @@ -94,9 +99,48 @@ user_uintptr_t make_user_ptr_owning(ptraddr_t addr, size_t len, user_ptr_perms_t return cheri_address_set(user_ptr, addr); }
+#ifndef arch_user_ptr_owning_perms_from_prot +static __always_inline +user_ptr_perms_t arch_user_ptr_owning_perms_from_prot(int prot, bool has_tag_access) +{ + return 0; +} +#define arch_user_ptr_owning_perms_from_prot arch_user_ptr_owning_perms_from_prot +#endif /* arch_user_ptr_owning_perms_from_prot */ + user_ptr_perms_t user_ptr_owning_perms_from_prot(int prot, bool has_tag_access) { - /* TODO [PCuABI] - capability permission conversion from memory permission */ - return (CHERI_PERMS_READ | CHERI_PERMS_WRITE | - CHERI_PERMS_EXEC | CHERI_PERMS_ROOTCAP); + user_ptr_perms_t perms = 0; + int used_prot = PROT_MAX_EXTRACT(prot) ? PROT_MAX_EXTRACT(prot) : prot; + + if (used_prot & PROT_READ) { + perms |= CHERI_PERM_LOAD; + if (has_tag_access) + perms |= CHERI_PERM_LOAD_CAP; + } + if (used_prot & PROT_WRITE) { + perms |= CHERI_PERM_STORE; + if (has_tag_access) + perms |= (CHERI_PERM_STORE_CAP | CHERI_PERM_STORE_LOCAL_CAP); + } + if (used_prot & PROT_EXEC) + perms |= CHERI_PERM_EXECUTE; + + /* Fetch any extra architecture specific permissions */ + perms |= arch_user_ptr_owning_perms_from_prot(used_prot, has_tag_access); + perms |= CHERI_PERMS_ROOTCAP; + + return perms; +} + +bool user_ptr_may_set_prot(user_uintptr_t user_ptr, int prot) +{ + user_ptr_perms_t perms = cheri_perms_get(user_ptr); + + if (((prot & PROT_READ) && !(perms & CHERI_PERM_LOAD)) || + ((prot & PROT_WRITE) && !(perms & CHERI_PERM_STORE)) || + ((prot & PROT_EXEC) && !(perms & CHERI_PERM_EXECUTE))) + return false; + + return true; }