Commit ccad8c13 authored by Deepak Gupta's avatar Deepak Gupta Committed by Paul Walmsley
Browse files

arch/riscv: add dual vdso creation logic and select vdso based on hw



Shadow stack instructions are taken from the Zimop ISA extension,
which is mandated on RVA23. Any userspace with shadow stack
instructions in it will fault on hardware that doesn't have support
for Zimop.  Thus, a shadow stack-enabled userspace can't be run on
hardware that doesn't support Zimop.

It's not known how Linux userspace providers will respond to this kind
of binary fragmentation.  In order to keep kernel portable across
different hardware, 'arch/riscv/kernel/vdso_cfi' is created which has
Makefile logic to compile 'arch/riscv/kernel/vdso' sources with CFI
flags, and 'arch/riscv/kernel/vdso.c' is modified to select the
appropriate vdso depending on whether the underlying CPU implements
the Zimop extension. Since the offset of vdso symbols will change due
to having two different vdso binaries, there is added logic to include
a new generated vdso offset header and dynamically select the offset
(like for rt_sigreturn).

Signed-off-by: default avatarDeepak Gupta <debug@rivosinc.com>
Acked-by: default avatarCharles Mirabile <cmirabil@redhat.com>
Tested-by: Andreas Korb <andreas.korb@aisec.fraunhofer.de> # QEMU, custom CVA6
Tested-by: default avatarValentin Haudiquet <valentin.haudiquet@canonical.com>
Link: https://patch.msgid.link/20251112-v5_user_cfi_series-v23-24-b55691eacf4f@rivosinc.com


[pjw@kernel.org: cleaned up patch description]
Signed-off-by: default avatarPaul Walmsley <pjw@kernel.org>
parent 37f57bd3
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -161,6 +161,8 @@ ifeq ($(CONFIG_MMU),y)
prepare: vdso_prepare
vdso_prepare: prepare0
	$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso include/generated/vdso-offsets.h
	$(if $(CONFIG_RISCV_USER_CFI),$(Q)$(MAKE) \
		$(build)=arch/riscv/kernel/vdso_cfi include/generated/vdso-cfi-offsets.h)
	$(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
		$(build)=arch/riscv/kernel/compat_vdso include/generated/compat_vdso-offsets.h)

@@ -168,6 +170,7 @@ endif
endif

vdso-install-y			+= arch/riscv/kernel/vdso/vdso.so.dbg
vdso-install-$(CONFIG_RISCV_USER_CFI)	+= arch/riscv/kernel/vdso_cfi/vdso-cfi.so.dbg
vdso-install-$(CONFIG_COMPAT)	+= arch/riscv/kernel/compat_vdso/compat_vdso.so.dbg

BOOT_TARGETS := Image Image.gz Image.bz2 Image.lz4 Image.lzma Image.lzo Image.zst Image.xz loader loader.bin xipImage vmlinuz.efi
+12 −1
Original line number Diff line number Diff line
@@ -18,9 +18,19 @@

#ifndef __ASSEMBLER__
#include <generated/vdso-offsets.h>
#ifdef CONFIG_RISCV_USER_CFI
#include <generated/vdso-cfi-offsets.h>
#endif

#ifdef CONFIG_RISCV_USER_CFI
#define VDSO_SYMBOL(base, name)							\
	(void __user *)((unsigned long)(base) + __vdso_##name##_offset)
	  (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZIMOP) ?			\
	  (void __user *)((unsigned long)(base) + __vdso_##name##_cfi_offset) :	\
	  (void __user *)((unsigned long)(base) + __vdso_##name##_offset))
#else
#define VDSO_SYMBOL(base, name)							\
	  ((void __user *)((unsigned long)(base) + __vdso_##name##_offset))
#endif

#ifdef CONFIG_COMPAT
#include <generated/compat_vdso-offsets.h>
@@ -33,6 +43,7 @@ extern char compat_vdso_start[], compat_vdso_end[];
#endif /* CONFIG_COMPAT */

extern char vdso_start[], vdso_end[];
extern char vdso_cfi_start[], vdso_cfi_end[];

#endif /* !__ASSEMBLER__ */

+1 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ obj-y += vendor_extensions/
obj-y	+= probes/
obj-y	+= tests/
obj-$(CONFIG_MMU) += vdso.o vdso/
obj-$(CONFIG_RISCV_USER_CFI) += vdso_cfi/

obj-$(CONFIG_RISCV_MISALIGNED)	+= traps_misaligned.o
obj-$(CONFIG_RISCV_MISALIGNED)	+= unaligned_access_speed.o
+7 −0
Original line number Diff line number Diff line
@@ -98,6 +98,13 @@ static struct __vdso_info compat_vdso_info __ro_after_init = {

static int __init vdso_init(void)
{
	/* Hart implements zimop, expose cfi compiled vdso */
	if (IS_ENABLED(CONFIG_RISCV_USER_CFI) &&
	    riscv_has_extension_unlikely(RISCV_ISA_EXT_ZIMOP)) {
		vdso_info.vdso_code_start = vdso_cfi_start;
		vdso_info.vdso_code_end = vdso_cfi_end;
	}

	__vdso_init(&vdso_info);
#ifdef CONFIG_COMPAT
	__vdso_init(&compat_vdso_info);
+20 −9
Original line number Diff line number Diff line
@@ -20,6 +20,10 @@ endif
ifdef VDSO_CFI_BUILD
CFI_MARCH = _zicfilp_zicfiss
CFI_FULL = -fcf-protection=full
CFI_SUFFIX = -cfi
OFFSET_SUFFIX = _cfi
ccflags-y += -DVDSO_CFI=1
asflags-y += -DVDSO_CFI=1
endif

# Files to link into the vdso
@@ -48,13 +52,20 @@ endif
CFLAGS_hwprobe.o += -fPIC

# Build rules
targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds
vdso_offsets := vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),)-offsets.h
vdso_o := vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),).o
vdso_so := vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),).so
vdso_so_dbg := vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),).so.dbg
vdso_lds := vdso.lds

targets := $(obj-vdso) $(vdso_so) $(vdso_so_dbg) $(vdso_lds)

obj-vdso := $(addprefix $(obj)/, $(obj-vdso))

obj-y += vdso.o
CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
obj-y += vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),).o
CPPFLAGS_$(vdso_lds) += -P -C -U$(ARCH)
ifneq ($(filter vgettimeofday, $(vdso-syms)),)
CPPFLAGS_vdso.lds += -DHAS_VGETTIMEOFDAY
CPPFLAGS_$(vdso_lds) += -DHAS_VGETTIMEOFDAY
endif

# Disable -pg to prevent insert call site
@@ -63,12 +74,12 @@ CFLAGS_REMOVE_getrandom.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS)
CFLAGS_REMOVE_hwprobe.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS)

# Force dependency
$(obj)/vdso.o: $(obj)/vdso.so
$(obj)/$(vdso_o): $(obj)/$(vdso_so)

# link rule for the .so file, .lds has to be first
$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE
$(obj)/$(vdso_so_dbg): $(obj)/$(vdso_lds) $(obj-vdso) FORCE
	$(call if_changed,vdsold_and_check)
LDFLAGS_vdso.so.dbg = -shared -soname=linux-vdso.so.1 \
LDFLAGS_$(vdso_so_dbg) = -shared -soname=linux-vdso.so.1 \
	--build-id=sha1 --eh-frame-hdr

# strip rule for the .so file
@@ -79,9 +90,9 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE
# Generate VDSO offsets using helper script
gen-vdsosym := $(src)/gen_vdso_offsets.sh
quiet_cmd_vdsosym = VDSOSYM $@
	cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
	cmd_vdsosym = $(NM) $< | $(gen-vdsosym) $(OFFSET_SUFFIX) | LC_ALL=C sort > $@

include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
include/generated/$(vdso_offsets): $(obj)/$(vdso_so_dbg) FORCE
	$(call if_changed,vdsosym)

# actual build commands
Loading