Implement the Morello-specific aspects of linux/cheri.h, that is:
* Override standard permission sets to include the appropriate Morello-specific permissions.
* Initialise the global root capabilities appropriately.
Signed-off-by: Kevin Brodsky kevin.brodsky@arm.com --- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/cheri.h | 11 ++++++ arch/arm64/kernel/morello.c | 71 ++++++++++++++++++++++++++-------- 3 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 arch/arm64/include/asm/cheri.h
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index e676991a97e7..b64f37575979 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -29,6 +29,7 @@ config ARM64 select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE select ARCH_HAS_KCOV + select HAVE_ARCH_CHERI_H select ARCH_HAS_USER_PTR_H select ARCH_HAS_KEEPINITRD select ARCH_HAS_MEMBARRIER_SYNC_CORE diff --git a/arch/arm64/include/asm/cheri.h b/arch/arm64/include/asm/cheri.h new file mode 100644 index 000000000000..eaae6ed88db5 --- /dev/null +++ b/arch/arm64/include/asm/cheri.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __ASM_CHERI_H +#define __ASM_CHERI_H + +#define CHERI_PERMS_READ \ + (CHERI_PERM_LOAD | CHERI_PERM_LOAD_CAP | ARM_CAP_PERMISSION_MUTABLE_LOAD) + +#define CHERI_PERMS_EXEC \ + (CHERI_PERM_EXECUTE | CHERI_PERM_SYSTEM_REGS | ARM_CAP_PERMISSION_EXECUTIVE) + +#endif /* __ASM_CHERI_H */ diff --git a/arch/arm64/kernel/morello.c b/arch/arm64/kernel/morello.c index 2a57104c2bd7..c9db2153d6de 100644 --- a/arch/arm64/kernel/morello.c +++ b/arch/arm64/kernel/morello.c @@ -5,10 +5,9 @@
#define pr_fmt(fmt) "morello: " fmt
-#include <cheriintrin.h> - #include <linux/cache.h> #include <linux/capability.h> +#include <linux/cheri.h> #include <linux/compat.h> #include <linux/mm.h> #include <linux/printk.h> @@ -21,10 +20,6 @@ #include <asm/morello.h> #include <asm/ptrace.h>
-#ifdef CONFIG_CHERI_PURECAP_UABI -#include <cheriintrin.h> -#endif - /* Private functions implemented in morello.S */ void __morello_cap_lo_hi_tag(uintcap_t cap, u64 *lo_val, u64 *hi_val, u8 *tag); @@ -41,6 +36,8 @@ static uintcap_t morello_sentry_unsealcap __ro_after_init; #define DDC_RESET_VAL_LOW_64 0x0 #define DDC_RESET_VAL_HIGH_64 0xffffc00000010005ULL
+#define CAP_OTYPE_FIELD_BITS 15 + uintcap_t morello_get_root_cap(void) { return morello_root_cap; @@ -294,8 +291,8 @@ static void __init check_root_cap(uintcap_t cap) __morello_cap_lo_hi_tag(cap, &lo_val, &hi_val, &tag);
/* - * Check that DDC has the reset value, otherwise morello_root_cap and - * all capabilities derived from it (especially those exposed to + * Check that DDC has the reset value, otherwise root capabilities and + * all capabilities derived from them (notably those exposed to * userspace) may not be reliable. */ if (!(tag == 1 && @@ -304,22 +301,62 @@ static void __init check_root_cap(uintcap_t cap) pr_warn("DDC does not have its reset value, this may be a firmware bug\n"); }
+#define __build_cap(root, perms, length, ...) \ +({ \ + uintcap_t c = (root); \ + size_t len = (length); \ + \ + c = cheri_perms_and(c, (perms)); \ + if (len) \ + c = cheri_bounds_set(c, len); \ + \ + c; \ +}) +#define build_cap(root, perms, ...) __build_cap((root), (perms), ##__VA_ARGS__, 0) + static int __init morello_cap_init(void) { -#ifdef CONFIG_CHERI_PURECAP_UABI - uintcap_t ctemp; -#endif + uintcap_t root_cap; + cheri_perms_t perms; + + root_cap = (uintcap_t)cheri_ddc_get(); + check_root_cap(root_cap); + + /* Initialise standard CHERI root capabilities. */ + + perms = CHERI_PERMS_ROOTCAP | + CHERI_PERMS_READ | CHERI_PERMS_WRITE | CHERI_PERMS_EXEC | + ARM_CAP_PERMISSION_BRANCH_SEALED_PAIR | + CHERI_PERM_SEAL | CHERI_PERM_UNSEAL | + ARM_CAP_PERMISSION_COMPARTMENT_ID; + /* Same upper limit as for access_ok() and __uaccess_mask_ptr() */ + cheri_user_root_allperms_cap = build_cap(root_cap, perms, TASK_SIZE_MAX); + + perms = CHERI_PERMS_ROOTCAP | + CHERI_PERMS_READ | CHERI_PERMS_WRITE | CHERI_PERMS_EXEC | + ARM_CAP_PERMISSION_BRANCH_SEALED_PAIR; + cheri_user_root_cap = build_cap(cheri_user_root_allperms_cap, perms); + + perms = CHERI_PERM_GLOBAL | CHERI_PERM_SEAL | CHERI_PERM_UNSEAL; + /* + * Includes all object types, not a final decision - some of them may + * be later reserved to the kernel. + */ + cheri_user_root_seal_cap = build_cap(cheri_user_root_allperms_cap, + perms, 1u << CAP_OTYPE_FIELD_BITS);
- morello_root_cap = (uintcap_t)cheri_ddc_get(); + perms = CHERI_PERM_GLOBAL | ARM_CAP_PERMISSION_COMPARTMENT_ID; + /* Maximum userspace bounds for the time being. */ + cheri_user_root_cid_cap = build_cap(cheri_user_root_allperms_cap, perms);
- check_root_cap(morello_root_cap); + /* Initialise Morello-specific root capabilities. */ + morello_root_cap = root_cap;
#ifdef CONFIG_CHERI_PURECAP_UABI /* Initialize a capability able to unseal sentry capabilities. */ - ctemp = cheri_address_set(morello_root_cap, CHERI_OTYPE_SENTRY); - ctemp = cheri_bounds_set(ctemp, 1); - ctemp = cheri_perms_and(ctemp, CHERI_PERM_GLOBAL | CHERI_PERM_UNSEAL); - morello_sentry_unsealcap = ctemp; + perms = CHERI_PERM_GLOBAL | CHERI_PERM_UNSEAL; + morello_sentry_unsealcap = cheri_address_set(root_cap, CHERI_OTYPE_SENTRY); + morello_sentry_unsealcap = build_cap(morello_sentry_unsealcap, perms, 1); #endif
return 0;