Makefile | 2 +- arch/riscv/Kconfig | 37 +++++++++++++++++++++++++- arch/riscv/Makefile | 8 ++++++ arch/riscv/include/asm/asm.h | 2 +- arch/riscv/include/asm/linkage.h | 42 +++++++++++++++++++++++++++++ arch/riscv/include/asm/pgtable.h | 4 +++ arch/riscv/include/asm/scs.h | 48 +++++++++++++++++++++++++++------- arch/riscv/include/asm/sections.h | 22 ++++++++++++++++ arch/riscv/include/asm/thread_info.h | 10 +++++-- arch/riscv/kernel/asm-offsets.c | 1 + arch/riscv/kernel/compat_vdso/Makefile | 2 +- arch/riscv/kernel/entry.S | 21 ++++++++------- arch/riscv/kernel/head.S | 23 ++++++++++++++-- arch/riscv/kernel/vdso/Makefile | 2 +- arch/riscv/kernel/vmlinux.lds.S | 12 +++++++++ arch/riscv/lib/memset.S | 6 ++--- arch/riscv/mm/init.c | 29 +++++++++++++++----- include/linux/init_task.h | 5 ++++ include/linux/scs.h | 26 +++++++++++++++++- init/init_task.c | 12 +++++++-- kernel/scs.c | 38 ++++++++++++++++++++++++--- mm/Kconfig | 6 +++++ 22 files changed, 314 insertions(+), 44 deletions(-)
This patch series enables fine grained control-flow integrity for kernel on riscv platform. I did send out a RFC patchset [1] more than an year ago. Since it's been a while, I am resetting the versioning and calling it a RFC due to following reasons - This is first (in a while) and I may have missed things. - Earlier patchset were not fine-grained kcfi. This one is. - Toolchain used to compile kernel is still in development. - On asm indirect callsites, setting up label need toolchain support. It is based on 6.16-rc1 with user cfi enabling patchset(v18)[2] applied on it. Hardware guarantee on kernel's control flow integrity is enforced via zicfilp and zicfiss riscv cpu extensions. Please take a look at user cfi enabling patchset for more details and references on these cpu extensions. Toolchain ---------- As mentioned earlier toolchain used to develop this patchset are still in development. But you can grab them here [3]. This is how I configure and compile toolchain. $ ./riscv-gnu-toolchain/configure \ --prefix=/scratch/debug/open_src/sifive_cfi_toolchain/INSTALL_funcsig \ --with-arch=rv64gc_zicfilp_zicfiss_zicsr_zifencei_zimop_zcmop \ --enable-debug-info --enable-linux --disable-gdb --with-abi=lp64d \ --with-label-scheme=func-sig \ --with-linux-headers-src=/scratch/debug/linux/kbuild/usr/include $ make -j$(nproc) If `-fcf-protection=full` is selected, toolchain is enabled to generate labeled landing pad instruction at the start of the function. And shadow stack push to save return address and sspopchk instruction in the return path. riscv kernel control-flow integrity ------------------------------------ As with normal user software, enabling kernel control flow integrity also require forward control flow integrity and backward control flow integrity. This patchset introduces CONFIG_RISCV_KERNEL_CFI config, hw assisted riscv kernel cfi is enabled only when `CONFIG_RISCV_KERNEL_CFI=y`. Selecting CONFIG_RISCV_KERNEL_CFI is dependent on CONFIG_RISCV_USER_CFI. To compile kernel, please clone the toolchain (link provided above), build it and use that toolchain bits to compile the kernel. When you do `menuconfig` select `Kernel features` --> `riscv userspace control flow integrity`. When you select `riscv userspace control flow integrity`, then `hw assisted riscv kernel control flow integrity (kcfi)` will show up. Select both and build. I have tested kcfi enabled kernel with full userspace exercising (unlabeled landing pads) cfi starting with init process. In my limited testing, this boots. There are some wrinkles around what labeling scheme should be used for vDSO object. This patchset is using labeled landing pads for vDSO. We may end up using unlabeled landing pad for vDSO for maximum compatibility. But that's a future discussion. Qemu command line to launch: /scratch/debug/open_src/qemu/build_zicfilp/qemu-system-riscv64 \ -nographic \ -monitor telnet:127.0.0.1:55555,server,nowait \ -machine virt \ -cpu rv64,zicond=true,zicfilp=true,zicfiss=true,zimop=true,zcmop=true,v=true,vlen=256,vext_spec=v1.0,zbb=true,zcb=true,zbkb=true,zacas=true \ -smp 2 \ -m 8G \ -object rng-random,filename=/dev/urandom,id=rng0 \ -device virtio-rng-device,rng=rng0 \ -drive file=/scratch/debug/open_src/zisslpcfi-toolchain/buildroot/output/images/rootfs.ext2,format=raw,id=hd0 \ -append "root=/dev/vda rw, no_hash_pointers, loglevel=8, crashkernel=256M, console=ttyS0, riscv_nousercfi=all" \ -serial mon:stdio \ -kernel /scratch/debug/linux/kbuild/arch/riscv/boot/Image \ -device e1000,netdev=net0 \ -netdev user,id=net0,hostfwd=tcp::10022-:22 \ -virtfs local,path=/scratch/debug/sources/spectacles,mount_tag=host0,security_model=passthrough,id=host0\ -bios /scratch/debug/open_src/opensbi/build/platform/generic/firmware/fw_jump.bin Backward kernel control flow integrity --------------------------------------- This patchset leverages on existing infrastructure of software based shadow call stack support in kernel. Differences between software based shadow call stack and riscv hardware shadow stack are: - software shadow call stack is writeable while riscv hardware shadow stack is writeable only via specific shadow stack instructions. - software shadow call stack grows from low memory to high memory while riscv hardware shadow stack grows from high memory to low memory (like a normal stack). - software shadow call stack on riscv uses `gp` register to hold shadow stack pointer while riscv hardware shadow stack has dedicated `CSR_SSP` register. Thus its ideal use existing shadow call stack plumbing and create hooks into it to apply riscv hardware shadow stack mechanisms on it. This patchset introduces `CONFIG_ARCH_HAS_KERNEL_SHADOW_STACK` along the lines of `CONFIG_ARCH_HAS_USER_SHADOW_STACK`. Forward kernel control-flow integrity -------------------------------------- Enabling forward kernel control-flow integrity is mostly toolchain work where it emits a landing pad instruction at the start of address-taken function. zicfilp allows landing pads to be labeled with a 20-bit immediate value. Compiler used here is following the scheme of normalizing function prototype to a string using C++ itanium rules (with some modifications). See more details here [4]. Compiler generates a 128bit md5 hash over this string and uses first non-zero (scanning from MSB) 20bit segment from the 128-bit hash as label value. This is still a work in progress and feedback/comments are welcome. I would like to thank Monk Chiang and Kito Cheng for helping and continue to support from the toolchain side. [1] - https://lore.kernel.org/lkml/CABCJKuf5Jg5g3FVpU22vNUo4UituPEM7QwvcVP8YWrvSPK+onA@mail.gmail.com/T/#m7d342d8728f9a23daed5319dac66201cc680b640 [2] - https://lore.kernel.org/all/20250711-v5_user_cfi_series-v18-0-a8ee62f9f38e@rivosinc.com/ [3] - https://github.com/sifive/riscv-gnu-toolchain/tree/cfi-dev [4] - https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/434 To: Paul Walmsley <paul.walmsley@sifive.com> To: Palmer Dabbelt <palmer@dabbelt.com> To: Albert Ou <aou@eecs.berkeley.edu> To: Alexandre Ghiti <alex@ghiti.fr> To: Masahiro Yamada <masahiroy@kernel.org> To: Nathan Chancellor <nathan@kernel.org> To: Nicolas Schier <nicolas.schier@linux.dev> To: Andrew Morton <akpm@linux-foundation.org> To: David Hildenbrand <david@redhat.com> To: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> To: Liam R. Howlett <Liam.Howlett@oracle.com> To: Vlastimil Babka <vbabka@suse.cz> To: Mike Rapoport <rppt@kernel.org> To: Suren Baghdasaryan <surenb@google.com> To: Michal Hocko <mhocko@suse.com> To: Nick Desaulniers <nick.desaulniers+lkml@gmail.com> To: Bill Wendling <morbo@google.com> To: Monk Chiang <monk.chiang@sifive.com> To: Kito Cheng <kito.cheng@sifive.com> To: Justin Stitt <justinstitt@google.com> Cc: linux-riscv@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linux-kbuild@vger.kernel.org Cc: linux-mm@kvack.org Cc: llvm@lists.linux.dev Cc: rick.p.edgecombe@intel.com Cc: broonie@kernel.org Cc: cleger@rivosinc.com Cc: samitolvanen@google.com Cc: apatel@ventanamicro.com Cc: ajones@ventanamicro.com Cc: conor.dooley@microchip.com Cc: charlie@rivosinc.com Cc: samuel.holland@sifive.com Cc: bjorn@rivosinc.com Cc: fweimer@redhat.com Cc: jeffreyalaw@gmail.com Cc: heinrich.schuchardt@canonical.com Cc: monk.chiang@sifive.com Cc: andrew@sifive.com Cc: ved@rivosinc.com Signed-off-by: Deepak Gupta <debug@rivosinc.com> --- Deepak Gupta (11): riscv: add landing pad for asm routines. riscv: update asm call site in `call_on_irq_stack` to setup correct label riscv: indirect jmp in asm that's static in nature to use sw guarded jump riscv: exception handlers can be software guarded transfers riscv: enable landing pad enforcement mm: Introduce ARCH_HAS_KERNEL_SHADOW_STACK scs: place init shadow stack in .shadowstack section riscv/mm: prepare shadow stack for init task riscv: scs: add hardware shadow stack support to scs scs: generic scs code updated to leverage hw assisted shadow stack riscv: Kconfig & Makefile for riscv kernel control flow integrity Makefile | 2 +- arch/riscv/Kconfig | 37 +++++++++++++++++++++++++- arch/riscv/Makefile | 8 ++++++ arch/riscv/include/asm/asm.h | 2 +- arch/riscv/include/asm/linkage.h | 42 +++++++++++++++++++++++++++++ arch/riscv/include/asm/pgtable.h | 4 +++ arch/riscv/include/asm/scs.h | 48 +++++++++++++++++++++++++++------- arch/riscv/include/asm/sections.h | 22 ++++++++++++++++ arch/riscv/include/asm/thread_info.h | 10 +++++-- arch/riscv/kernel/asm-offsets.c | 1 + arch/riscv/kernel/compat_vdso/Makefile | 2 +- arch/riscv/kernel/entry.S | 21 ++++++++------- arch/riscv/kernel/head.S | 23 ++++++++++++++-- arch/riscv/kernel/vdso/Makefile | 2 +- arch/riscv/kernel/vmlinux.lds.S | 12 +++++++++ arch/riscv/lib/memset.S | 6 ++--- arch/riscv/mm/init.c | 29 +++++++++++++++----- include/linux/init_task.h | 5 ++++ include/linux/scs.h | 26 +++++++++++++++++- init/init_task.c | 12 +++++++-- kernel/scs.c | 38 ++++++++++++++++++++++++--- mm/Kconfig | 6 +++++ 22 files changed, 314 insertions(+), 44 deletions(-) --- base-commit: cc0fb5eb25ea00aefd49002b1dac796ea13fd2a0 change-id: 20250616-riscv_kcfi-f851fb2128bf -- - debug
Well I forgot to apply "RFC" prefix in subject. Sorry about that. -Deepak On Thu, Jul 24, 2025 at 04:36:53PM -0700, Deepak Gupta wrote: >This patch series enables fine grained control-flow integrity for kernel >on riscv platform. I did send out a RFC patchset [1] more than an year ago. >Since it's been a while, I am resetting the versioning and calling it a RFC >due to following reasons > >- This is first (in a while) and I may have missed things. >- Earlier patchset were not fine-grained kcfi. This one is. >- Toolchain used to compile kernel is still in development. >- On asm indirect callsites, setting up label need toolchain support. > >It is based on 6.16-rc1 with user cfi enabling patchset(v18)[2] applied on it. >Hardware guarantee on kernel's control flow integrity is enforced via zicfilp >and zicfiss riscv cpu extensions. Please take a look at user cfi enabling >patchset for more details and references on these cpu extensions. > >Toolchain >---------- >As mentioned earlier toolchain used to develop this patchset are still in >development. But you can grab them here [3]. This is how I configure and >compile toolchain. > >$ ./riscv-gnu-toolchain/configure \ >--prefix=/scratch/debug/open_src/sifive_cfi_toolchain/INSTALL_funcsig \ >--with-arch=rv64gc_zicfilp_zicfiss_zicsr_zifencei_zimop_zcmop \ >--enable-debug-info --enable-linux --disable-gdb --with-abi=lp64d \ >--with-label-scheme=func-sig \ >--with-linux-headers-src=/scratch/debug/linux/kbuild/usr/include > >$ make -j$(nproc) > >If `-fcf-protection=full` is selected, toolchain is enabled to generate >labeled landing pad instruction at the start of the function. And >shadow stack push to save return address and sspopchk instruction in >the return path. > >riscv kernel control-flow integrity >------------------------------------ > >As with normal user software, enabling kernel control flow integrity also >require forward control flow integrity and backward control flow integrity. >This patchset introduces CONFIG_RISCV_KERNEL_CFI config, hw assisted riscv >kernel cfi is enabled only when `CONFIG_RISCV_KERNEL_CFI=y`. Selecting >CONFIG_RISCV_KERNEL_CFI is dependent on CONFIG_RISCV_USER_CFI. > >To compile kernel, please clone the toolchain (link provided above), build >it and use that toolchain bits to compile the kernel. When you do `menuconfig` >select `Kernel features` --> `riscv userspace control flow integrity`. >When you select `riscv userspace control flow integrity`, then `hw assisted >riscv kernel control flow integrity (kcfi)` will show up. Select both and >build. > >I have tested kcfi enabled kernel with full userspace exercising (unlabeled >landing pads) cfi starting with init process. In my limited testing, this >boots. There are some wrinkles around what labeling scheme should be used >for vDSO object. This patchset is using labeled landing pads for vDSO. >We may end up using unlabeled landing pad for vDSO for maximum compatibility. >But that's a future discussion. > >Qemu command line to launch: >/scratch/debug/open_src/qemu/build_zicfilp/qemu-system-riscv64 \ > -nographic \ > -monitor telnet:127.0.0.1:55555,server,nowait \ > -machine virt \ > -cpu rv64,zicond=true,zicfilp=true,zicfiss=true,zimop=true,zcmop=true,v=true,vlen=256,vext_spec=v1.0,zbb=true,zcb=true,zbkb=true,zacas=true \ > -smp 2 \ > -m 8G \ > -object rng-random,filename=/dev/urandom,id=rng0 \ > -device virtio-rng-device,rng=rng0 \ > -drive file=/scratch/debug/open_src/zisslpcfi-toolchain/buildroot/output/images/rootfs.ext2,format=raw,id=hd0 \ > -append "root=/dev/vda rw, no_hash_pointers, loglevel=8, crashkernel=256M, console=ttyS0, riscv_nousercfi=all" \ > -serial mon:stdio \ > -kernel /scratch/debug/linux/kbuild/arch/riscv/boot/Image \ > -device e1000,netdev=net0 \ > -netdev user,id=net0,hostfwd=tcp::10022-:22 \ > -virtfs local,path=/scratch/debug/sources/spectacles,mount_tag=host0,security_model=passthrough,id=host0\ > -bios /scratch/debug/open_src/opensbi/build/platform/generic/firmware/fw_jump.bin > >Backward kernel control flow integrity >--------------------------------------- >This patchset leverages on existing infrastructure of software based shadow >call stack support in kernel. Differences between software based shadow call >stack and riscv hardware shadow stack are: > >- software shadow call stack is writeable while riscv hardware shadow stack > is writeable only via specific shadow stack instructions. > >- software shadow call stack grows from low memory to high memory while riscv > hardware shadow stack grows from high memory to low memory (like a normal > stack). > >- software shadow call stack on riscv uses `gp` register to hold shadow stack > pointer while riscv hardware shadow stack has dedicated `CSR_SSP` register. > >Thus its ideal use existing shadow call stack plumbing and create hooks into >it to apply riscv hardware shadow stack mechanisms on it. > >This patchset introduces `CONFIG_ARCH_HAS_KERNEL_SHADOW_STACK` along the lines >of `CONFIG_ARCH_HAS_USER_SHADOW_STACK`. > >Forward kernel control-flow integrity >-------------------------------------- >Enabling forward kernel control-flow integrity is mostly toolchain work where >it emits a landing pad instruction at the start of address-taken function. >zicfilp allows landing pads to be labeled with a 20-bit immediate value. >Compiler used here is following the scheme of normalizing function prototype >to a string using C++ itanium rules (with some modifications). See more details >here [4]. Compiler generates a 128bit md5 hash over this string and uses >first non-zero (scanning from MSB) 20bit segment from the 128-bit hash as label >value. > >This is still a work in progress and feedback/comments are welcome. > >I would like to thank Monk Chiang and Kito Cheng for helping and continue to >support from the toolchain side. > >[1] - https://lore.kernel.org/lkml/CABCJKuf5Jg5g3FVpU22vNUo4UituPEM7QwvcVP8YWrvSPK+onA@mail.gmail.com/T/#m7d342d8728f9a23daed5319dac66201cc680b640 >[2] - https://lore.kernel.org/all/20250711-v5_user_cfi_series-v18-0-a8ee62f9f38e@rivosinc.com/ >[3] - https://github.com/sifive/riscv-gnu-toolchain/tree/cfi-dev >[4] - https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/434 > >To: Paul Walmsley <paul.walmsley@sifive.com> >To: Palmer Dabbelt <palmer@dabbelt.com> >To: Albert Ou <aou@eecs.berkeley.edu> >To: Alexandre Ghiti <alex@ghiti.fr> >To: Masahiro Yamada <masahiroy@kernel.org> >To: Nathan Chancellor <nathan@kernel.org> >To: Nicolas Schier <nicolas.schier@linux.dev> >To: Andrew Morton <akpm@linux-foundation.org> >To: David Hildenbrand <david@redhat.com> >To: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> >To: Liam R. Howlett <Liam.Howlett@oracle.com> >To: Vlastimil Babka <vbabka@suse.cz> >To: Mike Rapoport <rppt@kernel.org> >To: Suren Baghdasaryan <surenb@google.com> >To: Michal Hocko <mhocko@suse.com> >To: Nick Desaulniers <nick.desaulniers+lkml@gmail.com> >To: Bill Wendling <morbo@google.com> >To: Monk Chiang <monk.chiang@sifive.com> >To: Kito Cheng <kito.cheng@sifive.com> >To: Justin Stitt <justinstitt@google.com> >Cc: linux-riscv@lists.infradead.org >Cc: linux-kernel@vger.kernel.org >Cc: linux-kbuild@vger.kernel.org >Cc: linux-mm@kvack.org >Cc: llvm@lists.linux.dev >Cc: rick.p.edgecombe@intel.com >Cc: broonie@kernel.org >Cc: cleger@rivosinc.com >Cc: samitolvanen@google.com >Cc: apatel@ventanamicro.com >Cc: ajones@ventanamicro.com >Cc: conor.dooley@microchip.com >Cc: charlie@rivosinc.com >Cc: samuel.holland@sifive.com >Cc: bjorn@rivosinc.com >Cc: fweimer@redhat.com >Cc: jeffreyalaw@gmail.com >Cc: heinrich.schuchardt@canonical.com >Cc: monk.chiang@sifive.com >Cc: andrew@sifive.com >Cc: ved@rivosinc.com > >Signed-off-by: Deepak Gupta <debug@rivosinc.com> >--- >Deepak Gupta (11): > riscv: add landing pad for asm routines. > riscv: update asm call site in `call_on_irq_stack` to setup correct label > riscv: indirect jmp in asm that's static in nature to use sw guarded jump > riscv: exception handlers can be software guarded transfers > riscv: enable landing pad enforcement > mm: Introduce ARCH_HAS_KERNEL_SHADOW_STACK > scs: place init shadow stack in .shadowstack section > riscv/mm: prepare shadow stack for init task > riscv: scs: add hardware shadow stack support to scs > scs: generic scs code updated to leverage hw assisted shadow stack > riscv: Kconfig & Makefile for riscv kernel control flow integrity > > Makefile | 2 +- > arch/riscv/Kconfig | 37 +++++++++++++++++++++++++- > arch/riscv/Makefile | 8 ++++++ > arch/riscv/include/asm/asm.h | 2 +- > arch/riscv/include/asm/linkage.h | 42 +++++++++++++++++++++++++++++ > arch/riscv/include/asm/pgtable.h | 4 +++ > arch/riscv/include/asm/scs.h | 48 +++++++++++++++++++++++++++------- > arch/riscv/include/asm/sections.h | 22 ++++++++++++++++ > arch/riscv/include/asm/thread_info.h | 10 +++++-- > arch/riscv/kernel/asm-offsets.c | 1 + > arch/riscv/kernel/compat_vdso/Makefile | 2 +- > arch/riscv/kernel/entry.S | 21 ++++++++------- > arch/riscv/kernel/head.S | 23 ++++++++++++++-- > arch/riscv/kernel/vdso/Makefile | 2 +- > arch/riscv/kernel/vmlinux.lds.S | 12 +++++++++ > arch/riscv/lib/memset.S | 6 ++--- > arch/riscv/mm/init.c | 29 +++++++++++++++----- > include/linux/init_task.h | 5 ++++ > include/linux/scs.h | 26 +++++++++++++++++- > init/init_task.c | 12 +++++++-- > kernel/scs.c | 38 ++++++++++++++++++++++++--- > mm/Kconfig | 6 +++++ > 22 files changed, 314 insertions(+), 44 deletions(-) >--- >base-commit: cc0fb5eb25ea00aefd49002b1dac796ea13fd2a0 >change-id: 20250616-riscv_kcfi-f851fb2128bf >-- >- debug >
© 2016 - 2025 Red Hat, Inc.