]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
arch/riscv: add dual vdso creation logic and select vdso based on hw
authorDeepak Gupta <debug@rivosinc.com>
Mon, 26 Jan 2026 04:09:56 +0000 (21:09 -0700)
committerPaul Walmsley <pjw@kernel.org>
Thu, 29 Jan 2026 09:38:40 +0000 (02:38 -0700)
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: Deepak Gupta <debug@rivosinc.com>
Acked-by: Charles Mirabile <cmirabil@redhat.com>
Tested-by: Andreas Korb <andreas.korb@aisec.fraunhofer.de> # QEMU, custom CVA6
Tested-by: Valentin 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: Paul Walmsley <pjw@kernel.org>
arch/riscv/Makefile
arch/riscv/include/asm/vdso.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/vdso.c
arch/riscv/kernel/vdso/Makefile
arch/riscv/kernel/vdso/gen_vdso_offsets.sh
arch/riscv/kernel/vdso_cfi/Makefile [new file with mode: 0644]
arch/riscv/kernel/vdso_cfi/vdso-cfi.S [new file with mode: 0644]

index 41385bce8cc7e1068016e917a156e32ec6953a86..371da75a47f96089391f077966af6168f38a5059 100644 (file)
@@ -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
index f80357fe24d111cb3c4f53e8e9d20498798d22bd..35bf830a557612d8ed705b2f7830c9c22026f863 100644 (file)
 
 #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__ */
 
index 0a0a3fb02d6387efd977e4ddcef806b41ee862b9..cabb99cadfb6d1e1284d6b4e9ae76044d36949f5 100644 (file)
@@ -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
index 3a8e038b10a2dce9ee159232440b4c5ea0cba46b..43f70198ac3cdbbf7126086c58adefc3e4cdc7cf 100644 (file)
@@ -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);
index 272f1d837a80e723b0ce6a718f55607f76e552b0..a842dc034571da7ae24628ce95dee6be12a9bed7 100644 (file)
@@ -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
index c2e5613f3495109bc0faffca0a5782ade871a1f3..bd5d5afaaa147c085dc972f0a4a511265cd071ea 100755 (executable)
@@ -2,4 +2,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
 LC_ALL=C
-sed -n -e 's/^[0]\+\(0[0-9a-fA-F]*\) . \(__vdso_[a-zA-Z0-9_]*\)$/\#define \2_offset\t0x\1/p'
+SUFFIX=${1:-""}
+sed -n -e \
+'s/^[0]\+\(0[0-9a-fA-F]*\) . \(__vdso_[a-zA-Z0-9_]*\)$/\#define \2'$SUFFIX'_offset\t0x\1/p'
diff --git a/arch/riscv/kernel/vdso_cfi/Makefile b/arch/riscv/kernel/vdso_cfi/Makefile
new file mode 100644 (file)
index 0000000..8ebd190
--- /dev/null
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# RISC-V VDSO CFI Makefile
+# This Makefile builds the VDSO with CFI support when CONFIG_RISCV_USER_CFI is enabled
+
+# setting VDSO_CFI_BUILD triggers build for vdso differently
+VDSO_CFI_BUILD := 1
+
+# Set the source directory to the main vdso directory
+src := $(srctree)/arch/riscv/kernel/vdso
+
+# Copy all .S and .c files from vdso directory to vdso_cfi object build directory
+vdso_c_sources := $(wildcard $(src)/*.c)
+vdso_S_sources := $(wildcard $(src)/*.S)
+vdso_c_objects := $(addprefix $(obj)/, $(notdir $(vdso_c_sources)))
+vdso_S_objects := $(addprefix $(obj)/, $(notdir $(vdso_S_sources)))
+
+$(vdso_S_objects): $(obj)/%.S: $(src)/%.S
+       $(Q)cp $< $@
+
+$(vdso_c_objects): $(obj)/%.c: $(src)/%.c
+       $(Q)cp $< $@
+
+# Include the main VDSO Makefile which contains all the build rules and sources
+# The VDSO_CFI_BUILD variable will be passed to it to enable CFI compilation
+include $(src)/Makefile
diff --git a/arch/riscv/kernel/vdso_cfi/vdso-cfi.S b/arch/riscv/kernel/vdso_cfi/vdso-cfi.S
new file mode 100644 (file)
index 0000000..d426f6a
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2025 Rivos, Inc
+ */
+
+#define        vdso_start      vdso_cfi_start
+#define        vdso_end        vdso_cfi_end
+
+#define __VDSO_PATH "arch/riscv/kernel/vdso_cfi/vdso-cfi.so"
+
+#include "../vdso/vdso.S"