Modify vdso pointer to user pointer and provide the suitable bounded capability to purecap userspace using the memory reservation interface.
Signed-off-by: Amit Daniel Kachhap amitdaniel.kachhap@arm.com --- arch/arm64/include/asm/elf.h | 5 ++--- arch/arm64/include/asm/mmu.h | 2 +- arch/arm64/kernel/signal.c | 2 +- arch/arm64/kernel/vdso.c | 29 ++++++++++++++++++++++++----- 4 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index b54070e80867..55dcbda6b052 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -178,8 +178,7 @@ extern int purecap_setup_additional_pages(struct linux_binprm *bprm, * TODO [PCuABI]: Look into restricting the bounds of this capability to just * the vDSO pages, as currently the bounds are of the root user capability. */ -#define ARCH_DLINFO SETUP_DLINFO(uaddr_to_user_ptr_safe( \ - (elf_addr_t)current->mm->context.vdso)) +#define ARCH_DLINFO SETUP_DLINFO((user_uintptr_t)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) @@ -224,7 +223,7 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; SET_PERSONALITY_AARCH64(); \ })
-#define COMPAT_ARCH_DLINFO SETUP_DLINFO((elf_addr_t)current->mm->context.vdso) +#define COMPAT_ARCH_DLINFO SETUP_DLINFO((user_uintptr_t)current->mm->context.vdso)
#define compat_arch_setup_additional_pages aarch64_setup_additional_pages
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 12a7889f0a37..5febbcb23b48 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -23,7 +23,7 @@ typedef struct { void *sigpage; #endif refcount_t pinned; - void *vdso; + void __user *vdso; unsigned long flags; } mm_context_t;
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index a585d005f797..948766111204 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -1265,7 +1265,7 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka, if (ka->sa.sa_flags & SA_RESTORER) sigtramp = user_ptr_addr(ka->sa.sa_restorer); else - sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp); + sigtramp = VDSO_SYMBOL((user_uintptr_t)current->mm->context.vdso, sigtramp);
regs->regs[30] = sigtramp; } diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index 3121e70f598a..1fe873e9ef6c 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -8,6 +8,7 @@ */
#include <linux/cache.h> +#include <linux/cap_addr_mgmt.h> #include <linux/clocksource.h> #include <linux/elf.h> #include <linux/err.h> @@ -15,6 +16,7 @@ #include <linux/gfp.h> #include <linux/kernel.h> #include <linux/mm.h> +#include <linux/mman.h> #include <linux/sched.h> #include <linux/signal.h> #include <linux/slab.h> @@ -86,7 +88,16 @@ struct vdso_data *vdso_data = vdso_data_store.data; static int vdso_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *new_vma) { - current->mm->context.vdso = (void *)new_vma->vm_start; + if (reserv_is_supported(new_vma->vm_mm)) { + current->mm->context.vdso = (void __user *)make_user_ptr_owning( + reserv_vma_reserv_start(new_vma), + reserv_vma_reserv_len(new_vma), + reserv_vma_reserv_perms(new_vma)); + current->mm->context.vdso = user_ptr_set_addr(current->mm->context.vdso, + new_vma->vm_start); + } else { + current->mm->context.vdso = as_user_ptr(new_vma->vm_start); + }
return 0; } @@ -202,8 +213,9 @@ static int __setup_additional_pages(enum vdso_abi abi, struct linux_binprm *bprm, int uses_interp) { - unsigned long vdso_base, vdso_text_len, vdso_mapping_len; + unsigned long vdso_base, vdso_text_base, vdso_text_len, vdso_mapping_len; unsigned long gp_flags = 0; + user_uintptr_t user_ptr; void *ret;
BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES); @@ -227,14 +239,21 @@ static int __setup_additional_pages(enum vdso_abi abi, if (system_supports_bti_kernel()) gp_flags = VM_ARM64_BTI;
- vdso_base += VVAR_NR_PAGES * PAGE_SIZE; - mm->context.vdso = (void *)vdso_base; - ret = _install_special_mapping(mm, vdso_base, vdso_text_len, + vdso_text_base = vdso_base + VVAR_NR_PAGES * PAGE_SIZE; + ret = _install_special_mapping(mm, vdso_text_base, vdso_text_len, VM_READ|VM_EXEC|gp_flags| VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, vdso_info[abi].cm); if (IS_ERR(ret)) goto up_fail; + user_ptr = reserv_range_set_reserv(vdso_base, vdso_mapping_len, + user_ptr_owning_perms_from_prot(PROT_READ | PROT_EXEC, + true), true); + if (IS_ERR_VALUE(user_ptr)) { + ret = (void *)(ptraddr_t)user_ptr; + goto up_fail; + } + mm->context.vdso = (void __user *)(user_ptr + VVAR_NR_PAGES * PAGE_SIZE);
return 0;