Skip to content

Commit ccad8c1

Browse files
deepak0414Paul Walmsley
authored andcommitted
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: 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>
1 parent 37f57bd commit ccad8c1

8 files changed

Lines changed: 82 additions & 11 deletions

File tree

arch/riscv/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,16 @@ ifeq ($(CONFIG_MMU),y)
161161
prepare: vdso_prepare
162162
vdso_prepare: prepare0
163163
$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso include/generated/vdso-offsets.h
164+
$(if $(CONFIG_RISCV_USER_CFI),$(Q)$(MAKE) \
165+
$(build)=arch/riscv/kernel/vdso_cfi include/generated/vdso-cfi-offsets.h)
164166
$(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
165167
$(build)=arch/riscv/kernel/compat_vdso include/generated/compat_vdso-offsets.h)
166168

167169
endif
168170
endif
169171

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

173176
BOOT_TARGETS := Image Image.gz Image.bz2 Image.lz4 Image.lzma Image.lzo Image.zst Image.xz loader loader.bin xipImage vmlinuz.efi

arch/riscv/include/asm/vdso.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,19 @@
1818

1919
#ifndef __ASSEMBLER__
2020
#include <generated/vdso-offsets.h>
21+
#ifdef CONFIG_RISCV_USER_CFI
22+
#include <generated/vdso-cfi-offsets.h>
23+
#endif
2124

25+
#ifdef CONFIG_RISCV_USER_CFI
2226
#define VDSO_SYMBOL(base, name) \
23-
(void __user *)((unsigned long)(base) + __vdso_##name##_offset)
27+
(riscv_has_extension_unlikely(RISCV_ISA_EXT_ZIMOP) ? \
28+
(void __user *)((unsigned long)(base) + __vdso_##name##_cfi_offset) : \
29+
(void __user *)((unsigned long)(base) + __vdso_##name##_offset))
30+
#else
31+
#define VDSO_SYMBOL(base, name) \
32+
((void __user *)((unsigned long)(base) + __vdso_##name##_offset))
33+
#endif
2434

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

3545
extern char vdso_start[], vdso_end[];
46+
extern char vdso_cfi_start[], vdso_cfi_end[];
3647

3748
#endif /* !__ASSEMBLER__ */
3849

arch/riscv/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ obj-y += vendor_extensions/
7373
obj-y += probes/
7474
obj-y += tests/
7575
obj-$(CONFIG_MMU) += vdso.o vdso/
76+
obj-$(CONFIG_RISCV_USER_CFI) += vdso_cfi/
7677

7778
obj-$(CONFIG_RISCV_MISALIGNED) += traps_misaligned.o
7879
obj-$(CONFIG_RISCV_MISALIGNED) += unaligned_access_speed.o

arch/riscv/kernel/vdso.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ static struct __vdso_info compat_vdso_info __ro_after_init = {
9898

9999
static int __init vdso_init(void)
100100
{
101+
/* Hart implements zimop, expose cfi compiled vdso */
102+
if (IS_ENABLED(CONFIG_RISCV_USER_CFI) &&
103+
riscv_has_extension_unlikely(RISCV_ISA_EXT_ZIMOP)) {
104+
vdso_info.vdso_code_start = vdso_cfi_start;
105+
vdso_info.vdso_code_end = vdso_cfi_end;
106+
}
107+
101108
__vdso_init(&vdso_info);
102109
#ifdef CONFIG_COMPAT
103110
__vdso_init(&compat_vdso_info);

arch/riscv/kernel/vdso/Makefile

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ endif
2020
ifdef VDSO_CFI_BUILD
2121
CFI_MARCH = _zicfilp_zicfiss
2222
CFI_FULL = -fcf-protection=full
23+
CFI_SUFFIX = -cfi
24+
OFFSET_SUFFIX = _cfi
25+
ccflags-y += -DVDSO_CFI=1
26+
asflags-y += -DVDSO_CFI=1
2327
endif
2428

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

5054
# Build rules
51-
targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds
55+
vdso_offsets := vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),)-offsets.h
56+
vdso_o := vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),).o
57+
vdso_so := vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),).so
58+
vdso_so_dbg := vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),).so.dbg
59+
vdso_lds := vdso.lds
60+
61+
targets := $(obj-vdso) $(vdso_so) $(vdso_so_dbg) $(vdso_lds)
62+
5263
obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
5364

54-
obj-y += vdso.o
55-
CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
65+
obj-y += vdso$(if $(VDSO_CFI_BUILD),$(CFI_SUFFIX),).o
66+
CPPFLAGS_$(vdso_lds) += -P -C -U$(ARCH)
5667
ifneq ($(filter vgettimeofday, $(vdso-syms)),)
57-
CPPFLAGS_vdso.lds += -DHAS_VGETTIMEOFDAY
68+
CPPFLAGS_$(vdso_lds) += -DHAS_VGETTIMEOFDAY
5869
endif
5970

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

6576
# Force dependency
66-
$(obj)/vdso.o: $(obj)/vdso.so
77+
$(obj)/$(vdso_o): $(obj)/$(vdso_so)
6778

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

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

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

8798
# actual build commands

arch/riscv/kernel/vdso/gen_vdso_offsets.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
# SPDX-License-Identifier: GPL-2.0
33

44
LC_ALL=C
5-
sed -n -e 's/^[0]\+\(0[0-9a-fA-F]*\) . \(__vdso_[a-zA-Z0-9_]*\)$/\#define \2_offset\t0x\1/p'
5+
SUFFIX=${1:-""}
6+
sed -n -e \
7+
's/^[0]\+\(0[0-9a-fA-F]*\) . \(__vdso_[a-zA-Z0-9_]*\)$/\#define \2'$SUFFIX'_offset\t0x\1/p'
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
# RISC-V VDSO CFI Makefile
3+
# This Makefile builds the VDSO with CFI support when CONFIG_RISCV_USER_CFI is enabled
4+
5+
# setting VDSO_CFI_BUILD triggers build for vdso differently
6+
VDSO_CFI_BUILD := 1
7+
8+
# Set the source directory to the main vdso directory
9+
src := $(srctree)/arch/riscv/kernel/vdso
10+
11+
# Copy all .S and .c files from vdso directory to vdso_cfi object build directory
12+
vdso_c_sources := $(wildcard $(src)/*.c)
13+
vdso_S_sources := $(wildcard $(src)/*.S)
14+
vdso_c_objects := $(addprefix $(obj)/, $(notdir $(vdso_c_sources)))
15+
vdso_S_objects := $(addprefix $(obj)/, $(notdir $(vdso_S_sources)))
16+
17+
$(vdso_S_objects): $(obj)/%.S: $(src)/%.S
18+
$(Q)cp $< $@
19+
20+
$(vdso_c_objects): $(obj)/%.c: $(src)/%.c
21+
$(Q)cp $< $@
22+
23+
# Include the main VDSO Makefile which contains all the build rules and sources
24+
# The VDSO_CFI_BUILD variable will be passed to it to enable CFI compilation
25+
include $(src)/Makefile
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright 2025 Rivos, Inc
4+
*/
5+
6+
#define vdso_start vdso_cfi_start
7+
#define vdso_end vdso_cfi_end
8+
9+
#define __VDSO_PATH "arch/riscv/kernel/vdso_cfi/vdso-cfi.so"
10+
11+
#include "../vdso/vdso.S"

0 commit comments

Comments
 (0)