diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 348f294a7e2838..3d3cb2c64155bf 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -165,17 +165,21 @@ do { \ NEW_AUX_ENT(AT_IGNORE, 0); \ } while (0) +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES +struct linux_binprm; +extern int aarch64_setup_additional_pages(struct linux_binprm *bprm, + int uses_interp); + #ifdef CONFIG_CHERI_PURECAP_UABI +extern int purecap_setup_additional_pages(struct linux_binprm *bprm, + int uses_interp); +#define arch_setup_additional_pages purecap_setup_additional_pages #define ARCH_DLINFO SETUP_DLINFO(current->mm->context.vdso) #else /* !CONFIG_CHERI_PURECAP_UABI */ +#define arch_setup_additional_pages aarch64_setup_additional_pages #define ARCH_DLINFO SETUP_DLINFO((elf_addr_t)current->mm->context.vdso) #endif /* CONFIG_CHERI_PURECAP_UABI */ -#define ARCH_HAS_SETUP_ADDITIONAL_PAGES -struct linux_binprm; -extern int arch_setup_additional_pages(struct linux_binprm *bprm, - int uses_interp); - /* 1GB of VA */ #ifdef CONFIG_COMPAT32 #define STACK_RND_MASK (test_thread_flag(TIF_32BIT) ? \ @@ -210,6 +214,8 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; #define COMPAT_ARCH_DLINFO SETUP_DLINFO(current->mm->context.vdso) +#define compat_arch_setup_additional_pages aarch64_setup_additional_pages + #else /* !CONFIG_COMPAT64 */ /* AArch32 registers. */ diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h index 77b0137815e6ab..a056e8eea728ac 100644 --- a/arch/arm64/include/asm/vdso.h +++ b/arch/arm64/include/asm/vdso.h @@ -18,6 +18,7 @@ extern char vdso_start[], vdso_end[]; extern char vdso32_start[], vdso32_end[]; +extern char vdso_purecap_start[], vdso_purecap_end[]; #endif /* !__ASSEMBLER__ */ diff --git a/arch/arm64/include/asm/vdso/gettimeofday.h b/arch/arm64/include/asm/vdso/gettimeofday.h index 075f51c4ed5e06..c08702bc1f9a72 100644 --- a/arch/arm64/include/asm/vdso/gettimeofday.h +++ b/arch/arm64/include/asm/vdso/gettimeofday.h @@ -102,6 +102,32 @@ const struct vdso_data *__arch_get_vdso_data(void) return vd; } +static __always_inline +const struct vdso_time_data *__arch_get_vdso_u_time_data(void) +{ + const struct vdso_time_data *ret; + + asm(".hidden vdso_u_time_data\n\t" + "adrp %0, vdso_u_time_data\n\t" + "add %0, %0, #:lo12:vdso_u_time_data" + : "=C"(ret)); + return ret; +} + +static __always_inline +const struct vdso_rng_data *__arch_get_vdso_u_rng_data(void) +{ + const struct vdso_rng_data *ret; + + asm(".hidden vdso_u_rng_data\n\t" + "adrp %0, vdso_u_rng_data\n\t" + "add %0, %0, #:lo12:vdso_u_rng_data" + : "=C"(ret)); + return ret; +} + +#define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data +#define __arch_get_vdso_u_rng_data __arch_get_vdso_u_rng_data #else /* !__CHERI_PURE_CAPABILITY__ */ #if IS_ENABLED(CONFIG_CC_IS_GCC) && IS_ENABLED(CONFIG_PAGE_SIZE_64KB) static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void) diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 6307c3ad2a6381..1980fe7ae4a17e 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -71,10 +71,12 @@ obj-$(CONFIG_ARM64_MTE) += mte.o obj-$(CONFIG_ARM64_MORELLO) += morello.o obj-y += vdso-wrap.o obj-$(CONFIG_COMPAT_VDSO) += vdso32-wrap.o +obj-$(CONFIG_CHERI_PURECAP_UABI) += vdso-purecap-wrap.o # Force dependency (vdso*-wrap.S includes vdso.so through incbin) $(obj)/vdso-wrap.o: $(obj)/vdso/vdso.so $(obj)/vdso32-wrap.o: $(obj)/vdso32/vdso.so +$(obj)/vdso-purecap-wrap.o: $(obj)/vdso-purecap/vdso.so obj-y += probes/ obj-y += head.o diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index e5398dc0395ccb..367f75fcbe147c 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -41,6 +41,11 @@ #endif #include #include +#if defined(CONFIG_CHERI_PURECAP_UABI) && !defined(SIGNAL_COMPAT64) +#include +#else +#include +#endif #define GCS_SIGNAL_CAP(addr) (((unsigned long)addr) & GCS_CAP_ADDR_MASK) diff --git a/arch/arm64/kernel/vdso-purecap-wrap.S b/arch/arm64/kernel/vdso-purecap-wrap.S new file mode 100644 index 00000000000000..b0bac3af49258d --- /dev/null +++ b/arch/arm64/kernel/vdso-purecap-wrap.S @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023 ARM Limited + */ + +#include +#include +#include +#include +#include + + .globl vdso_purecap_start, vdso_purecap_end + .section .rodata + .balign PAGE_SIZE +vdso_purecap_start: + .incbin "arch/arm64/kernel/vdso-purecap/vdso.so" + .balign PAGE_SIZE +vdso_purecap_end: + + .previous + +emit_aarch64_feature_1_and diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index c571bc104f8e91..44847009935292 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -32,6 +32,7 @@ enum vdso_abi { VDSO_ABI_AA64, VDSO_ABI_AA32, + VDSO_ABI_PURECAP, }; struct vdso_abi_info { @@ -56,6 +57,13 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = { .vdso_code_end = vdso32_end, }, #endif /* CONFIG_COMPAT_VDSO */ +#ifdef CONFIG_CHERI_PURECAP_UABI + [VDSO_ABI_PURECAP] = { + .name = "vdso_purecap", + .vdso_code_start = vdso_purecap_start, + .vdso_code_end = vdso_purecap_end, + }, +#endif /* CONFIG_CHERI_PURECAP_UABI */ }; static user_uintptr_t make_vdso_ptr(struct vm_area_struct *vdso_text_vma) @@ -340,6 +348,41 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) } #endif /* CONFIG_COMPAT32 */ +#ifdef CONFIG_CHERI_PURECAP_UABI +enum purecap_map { + PURECAP_MAP_VDSO, +}; + +static struct vm_special_mapping purecap_vdso_maps[] __ro_after_init = { + [PURECAP_MAP_VDSO] = { + .name = "[vdso]", + .mremap = vdso_mremap, + }, +}; + +static int __init purecap_vdso_init(void) +{ + vdso_info[VDSO_ABI_PURECAP].cm = &purecap_vdso_maps[PURECAP_MAP_VDSO]; + + return __vdso_init(VDSO_ABI_PURECAP); +} +arch_initcall(purecap_vdso_init); + +int purecap_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) +{ + struct mm_struct *mm = current->mm; + int ret; + + if (mmap_write_lock_killable(mm)) + return -EINTR; + + ret = __setup_additional_pages(VDSO_ABI_PURECAP, mm, bprm, uses_interp); + mmap_write_unlock(mm); + + return ret; +} +#endif /* CONFIG_CHERI_PURECAP_UABI */ + static struct vm_special_mapping aarch64_vdso_map __ro_after_init = { .name = "[vdso]", .mremap = vdso_mremap, @@ -353,7 +396,7 @@ static int __init vdso_init(void) } arch_initcall(vdso_init); -int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) +int aarch64_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mm_struct *mm = current->mm; int ret; diff --git a/tools/testing/selftests/arm64/morello/bootstrap.c b/tools/testing/selftests/arm64/morello/bootstrap.c index b36a058e63c88b..c5b678c4cabe6a 100644 --- a/tools/testing/selftests/arm64/morello/bootstrap.c +++ b/tools/testing/selftests/arm64/morello/bootstrap.c @@ -85,6 +85,7 @@ int verify_auxval(struct morello_auxv *auxv) case AT_PLATFORM: case AT_RANDOM: case AT_PHDR: + case AT_SYSINFO_EHDR: case AT_CHERI_EXEC_RX_CAP: case AT_CHERI_STACK_CAP: case AT_CHERI_SEAL_CAP: