From e2d149dedea9b07f10922b40e2f0dcfd82d1c0ff Mon Sep 17 00:00:00 2001 From: Aditya Deshpande Date: Tue, 3 Oct 2023 11:58:53 +0100 Subject: [PATCH 1/2] arm64: vDSO: Provide a purecap vDSO to userspace purecap programs Map the purecap vDSO into userspace application address space, therefore providing purecap userspace applications a purecap vDSO to use, and provide a capability to it in AT_SYSINFO_EHDR by updating ARCH_DLINFO. Redefine the aarch64 vDSO as the compat vDSO, therefore allowing both regular arm64 and purecap binaries to use a vDSO under PCuABI. Now that the purecap vDSO is mapped in purecap processes, instead of the standard aarch64 vDSO one, we also need to ensure that setup_return() uses the right offset for the sigret trampoline. This is done by including only the appropriate offsets header (which is possible as signal.c is built twice, once for purecap and once for compat64). The bootstrap Morello kselftest is also amended to expect AT_SYSINFO_EHDR to be a valid capability, not a null one. -- CHERI-Linux (Hesham): cherry-picked 21ed9c7 and fixed merge conflits: * Removed VVAR * Aligned with the current purecap-vdso paths and builds -- Signed-off-by: Aditya Deshpande Co-developed-by: Kevin Brodsky Signed-off-by: Kevin Brodsky Signed-off-by: Hesham Almatary --- arch/arm64/include/asm/elf.h | 16 ++++--- arch/arm64/include/asm/vdso.h | 1 + arch/arm64/kernel/Makefile | 2 + arch/arm64/kernel/signal.c | 5 +++ arch/arm64/kernel/vdso-purecap-wrap.S | 22 +++++++++ arch/arm64/kernel/vdso.c | 45 ++++++++++++++++++- .../selftests/arm64/morello/bootstrap.c | 1 + 7 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 arch/arm64/kernel/vdso-purecap-wrap.S 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/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: From 9579304983cf51b3be19b791c1a3535e1d6d5059 Mon Sep 17 00:00:00 2001 From: Hesham Almatary Date: Fri, 29 May 2026 09:40:22 +0100 Subject: [PATCH 2/2] Morello: implement missing purecap vDSO accessors vdso_u_time_data and vdso_u_rng_data were added after the original Morello port and purecap vDSO support. As a result, purecap users currently fall back to the generic accessors. However, the generic helpers return invalid capabilities because they derive capabilities from zero-sized linker-defined symbols. Implement purecap-specific accessors for these symbols, similar to __arch_get_vdso_data(), so tagged capabilities are returned to purecap userspace by deriving them from the valid vDSO mapping capability (PCC). Signed-off-by: Hesham Almatary --- arch/arm64/include/asm/vdso/gettimeofday.h | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) 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)