mbox series

[v6,00/33] riscv control-flow integrity for usermode

Message ID 20241008-v5_user_cfi_series-v6-0-60d9fe073f37@rivosinc.com
Headers show
Series riscv control-flow integrity for usermode | expand

Message

Deepak Gupta Oct. 8, 2024, 10:36 p.m. UTC
Basics and overview
===================

Software with larger attack surfaces (e.g. network facing apps like databases,
browsers or apps relying on browser runtimes) suffer from memory corruption
issues which can be utilized by attackers to bend control flow of the program
to eventually gain control (by making their payload executable). Attackers are
able to perform such attacks by leveraging call-sites which rely on indirect
calls or return sites which rely on obtaining return address from stack memory.

To mitigate such attacks, risc-v extension zicfilp enforces that all indirect
calls must land on a landing pad instruction `lpad` else cpu will raise software
check exception (a new cpu exception cause code on riscv).
Similarly for return flow, risc-v extension zicfiss extends architecture with

- `sspush` instruction to push return address on a shadow stack
- `sspopchk` instruction to pop return address from shadow stack
  and compare with input operand (i.e. return address on stack)
- `sspopchk` to raise software check exception if comparision above
  was a mismatch
- Protection mechanism using which shadow stack is not writeable via
  regular store instructions

More information an details can be found at extensions github repo [1].

Equivalent to landing pad (zicfilp) on x86 is `ENDBRANCH` instruction in Intel
CET [3] and branch target identification (BTI) [4] on arm.
Similarly x86's Intel CET has shadow stack [5] and arm64 has guarded control
stack (GCS) [6] which are very similar to risc-v's zicfiss shadow stack.

x86 already supports shadow stack for user mode and arm64 support for GCS in
usermode [7] is ongoing.

Kernel awareness for user control flow integrity
================================================

This series picks up Samuel Holland's envcfg changes [2] as well. So if those are
being applied independently, they should be removed from this series.

Enabling:

In order to maintain compatibility and not break anything in user mode, kernel
doesn't enable control flow integrity cpu extensions on binary by default.
Instead exposes a prctl interface to enable, disable and lock the shadow stack
or landing pad feature for a task. This allows userspace (loader) to enumerate
if all objects in its address space are compiled with shadow stack and landing
pad support and accordingly enable the feature. Additionally if a subsequent
`dlopen` happens on a library, user mode can take a decision again to disable
the feature (if incoming library is not compiled with support) OR terminate the
task (if user mode policy is strict to have all objects in address space to be
compiled with control flow integirty cpu feature). prctl to enable shadow stack
results in allocating shadow stack from virtual memory and activating for user
address space. x86 and arm64 are also following same direction due to similar
reason(s).

clone/fork:

On clone and fork, cfi state for task is inherited by child. Shadow stack is
part of virtual memory and is a writeable memory from kernel perspective
(writeable via a restricted set of instructions aka shadow stack instructions)
Thus kernel changes ensure that this memory is converted into read-only when
fork/clone happens and COWed when fault is taken due to sspush, sspopchk or
ssamoswap. In case `CLONE_VM` is specified and shadow stack is to be enabled,
kernel will automatically allocate a shadow stack for that clone call.

map_shadow_stack:

x86 introduced `map_shadow_stack` system call to allow user space to explicitly
map shadow stack memory in its address space. It is useful to allocate shadow
for different contexts managed by a single thread (green threads or contexts)
risc-v implements this system call as well.

signal management:

If shadow stack is enabled for a task, kernel performs an asynchronous control
flow diversion to deliver the signal and eventually expects userspace to issue
sigreturn so that original execution can be resumed. Even though resume context
is prepared by kernel, it is in user space memory and is subject to memory
corruption and corruption bugs can be utilized by attacker in this race window
to perform arbitrary sigreturn and eventually bypass cfi mechanism.
Another issue is how to ensure that cfi related state on sigcontext area is not
trampled by legacy apps or apps compiled with old kernel headers.

In order to mitigate control-flow hijacting, kernel prepares a token and place
it on shadow stack before signal delivery and places address of token in
sigcontext structure. During sigreturn, kernel obtains address of token from
sigcontext struture, reads token from shadow stack and validates it and only
then allow sigreturn to succeed. Compatiblity issue is solved by adopting
dynamic sigcontext management introduced for vector extension. This series
re-factor the code little bit to allow future sigcontext management easy (as
proposed by Andy Chiu from SiFive)

config and compilation:

Introduce a new risc-v config option `CONFIG_RISCV_USER_CFI`. Selecting this
config option picks the kernel support for user control flow integrity. This
optin is presented only if toolchain has shadow stack and landing pad support.
And is on purpose guarded by toolchain support. Reason being that eventually
vDSO also needs to be compiled in with shadow stack and landing pad support.
vDSO compile patches are not included as of now because landing pad labeling
scheme is yet to settle for usermode runtime.

To get more information on kernel interactions with respect to
zicfilp and zicfiss, patch series adds documentation for
`zicfilp` and `zicfiss` in following:
Documentation/arch/riscv/zicfiss.rst
Documentation/arch/riscv/zicfilp.rst

How to test this series
=======================

Toolchain
---------
$ git clone git@github.com:sifive/riscv-gnu-toolchain.git -b cfi-dev
$ riscv-gnu-toolchain/configure --prefix=<path-to-where-to-build> --with-arch=rv64gc_zicfilp_zicfiss --enable-linux --disable-gdb  --with-extra-multilib-test="rv64gc_zicfilp_zicfiss-lp64d:-static"
$ make -j$(nproc)

Qemu
----
$ git clone git@github.com:deepak0414/qemu.git -b zicfilp_zicfiss_ratified_master_july11
$ cd qemu
$ mkdir build
$ cd build
$ ../configure --target-list=riscv64-softmmu
$ make -j$(nproc)

Opensbi
-------
$ git clone git@github.com:deepak0414/opensbi.git -b v6_cfi_spec_split_opensbi
$ make CROSS_COMPILE=<your riscv toolchain> -j$(nproc) PLATFORM=generic

Linux
-----
Running defconfig is fine. CFI is enabled by default if the toolchain
supports it.

$ make ARCH=riscv CROSS_COMPILE=<path-to-cfi-riscv-gnu-toolchain>/build/bin/riscv64-unknown-linux-gnu- -j$(nproc) defconfig
$ make ARCH=riscv CROSS_COMPILE=<path-to-cfi-riscv-gnu-toolchain>/build/bin/riscv64-unknown-linux-gnu- -j$(nproc)

Branch where user cfi enabling patches are maintained
https://github.com/deepak0414/linux-riscv-cfi/tree/vdso_user_cfi_v6.12-rc1

In case you're building your own rootfs using toolchain, please make sure you
pick following patch to ensure that vDSO compiled with lpad and shadow stack.

"arch/riscv: compile vdso with landing pad"

Running
-------

Modify your qemu command to have:
-bios <path-to-cfi-opensbi>/build/platform/generic/firmware/fw_dynamic.bin
-cpu rv64,zicfilp=true,zicfiss=true,zimop=true,zcmop=true

vDSO related Opens (in the flux)
=================================

I am listing these opens for laying out plan and what to expect in future
patch sets. And of course for the sake of discussion.

Shadow stack and landing pad enabling in vDSO
----------------------------------------------
vDSO must have shadow stack and landing pad support compiled in for task
to have shadow stack and landing pad support. This patch series doesn't
enable that (yet). Enabling shadow stack support in vDSO should be
straight forward (intend to do that in next versions of patch set). Enabling
landing pad support in vDSO requires some collaboration with toolchain folks
to follow a single label scheme for all object binaries. This is necessary to
ensure that all indirect call-sites are setting correct label and target landing
pads are decorated with same label scheme.

How many vDSOs
---------------
Shadow stack instructions are carved out of zimop (may be operations) and if CPU
doesn't implement zimop, they're illegal instructions. Kernel could be running on
a CPU which may or may not implement zimop. And thus kernel will have to carry 2
different vDSOs and expose the appropriate one depending on whether CPU implements
zimop or not.

References
==========
[1] - https://github.com/riscv/riscv-cfi
[2] - https://lore.kernel.org/all/20240814081126.956287-1-samuel.holland@sifive.com/
[3] - https://lwn.net/Articles/889475/
[4] - https://developer.arm.com/documentation/109576/0100/Branch-Target-Identification
[5] - https://www.intel.com/content/dam/develop/external/us/en/documents/catc17-introduction-intel-cet-844137.pdf
[6] - https://lwn.net/Articles/940403/
[7] - https://lore.kernel.org/all/20241001-arm64-gcs-v13-0-222b78d87eee@kernel.org/

To: Thomas Gleixner <tglx@linutronix.de>
To: Ingo Molnar <mingo@redhat.com>
To: Borislav Petkov <bp@alien8.de>
To: Dave Hansen <dave.hansen@linux.intel.com>
To: x86@kernel.org
To: H. Peter Anvin <hpa@zytor.com>
To: Andrew Morton <akpm@linux-foundation.org>
To: Liam R. Howlett <Liam.Howlett@oracle.com>
To: Vlastimil Babka <vbabka@suse.cz>
To: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
To: Paul Walmsley <paul.walmsley@sifive.com>
To: Palmer Dabbelt <palmer@dabbelt.com>
To: Albert Ou <aou@eecs.berkeley.edu>
To: Conor Dooley <conor@kernel.org>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Arnd Bergmann <arnd@arndb.de>
To: Christian Brauner <brauner@kernel.org>
To: Peter Zijlstra <peterz@infradead.org>
To: Oleg Nesterov <oleg@redhat.com>
To: Eric Biederman <ebiederm@xmission.com>
To: Kees Cook <kees@kernel.org>
To: Jonathan Corbet <corbet@lwn.net>
To: Shuah Khan <shuah@kernel.org>
Cc: linux-kernel@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: linux-riscv@lists.infradead.org
Cc: devicetree@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kselftest@vger.kernel.org
Cc: alistair.francis@wdc.com
Cc: richard.henderson@linaro.org
Cc: jim.shu@sifive.com
Cc: andybnac@gmail.com
Cc: kito.cheng@sifive.com
Cc: charlie@rivosinc.com
Cc: atishp@rivosinc.com
Cc: evan@rivosinc.com
Cc: cleger@rivosinc.com
Cc: alexghiti@rivosinc.com
Cc: samitolvanen@google.com
Cc: broonie@kernel.org
Cc: rick.p.edgecombe@intel.com

Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
changelog
---------

v6:
- Picked up Samuel Holland's changes as is with `envcfg` placed in
  `thread` instead of `thread_info`
- fixed unaligned newline escapes in kselftest
- cleaned up messages in kselftest and included test output in commit message
- fixed a bug in clone path reported by Zong Li
- fixed a build issue if CONFIG_RISCV_ISA_V is not selected
  (this was introduced due to re-factoring signal context
  management code)

v5:
- rebased on v6.12-rc1
- Fixed schema related issues in device tree file
- Fixed some of the documentation related issues in zicfilp/ss.rst
  (style issues and added index)
- added `SHADOW_STACK_SET_MARKER` so that implementation can define base
  of shadow stack.
- Fixed warnings on definitions added in usercfi.h when
  CONFIG_RISCV_USER_CFI is not selected.
- Adopted context header based signal handling as proposed by Andy Chiu
- Added support for enabling kernel mode access to shadow stack using
  FWFT
  (https://github.com/riscv-non-isa/riscv-sbi-doc/blob/master/src/ext-firmware-features.adoc)
- Link to v5: https://lore.kernel.org/r/20241001-v5_user_cfi_series-v1-0-3ba65b6e550f@rivosinc.com
  (Note: I had an issue in my workflow due to which version number wasn't
  picked up correctly while sending out patches)

v4:
- rebased on 6.11-rc6
- envcfg: Converged with Samuel Holland's patches for envcfg management on per-
thread basis.
- vma_is_shadow_stack is renamed to is_vma_shadow_stack
- picked up Mark Brown's `ARCH_HAS_USER_SHADOW_STACK` patch
- signal context: using extended context management to maintain compatibility.
- fixed `-Wmissing-prototypes` compiler warnings for prctl functions
- Documentation fixes and amending typos.
- Link to v4: https://lore.kernel.org/all/20240912231650.3740732-1-debug@rivosinc.com/

v3:
- envcfg
  logic to pick up base envcfg had a bug where `ENVCFG_CBZE` could have been
  picked on per task basis, even though CPU didn't implement it. Fixed in
   this series.

- dt-bindings
  As suggested, split into separate commit. fixed the messaging that spec is
  in public review

- arch_is_shadow_stack change
  arch_is_shadow_stack changed to vma_is_shadow_stack

- hwprobe
  zicfiss / zicfilp if present will get enumerated in hwprobe

- selftests
  As suggested, added object and binary filenames to .gitignore
  Selftest binary anyways need to be compiled with cfi enabled compiler which
  will make sure that landing pad and shadow stack are enabled. Thus removed
  separate enable/disable tests. Cleaned up tests a bit.

- Link to v3: https://lore.kernel.org/lkml/20240403234054.2020347-1-debug@rivosinc.com/

v2:
- Using config `CONFIG_RISCV_USER_CFI`, kernel support for riscv control flow
  integrity for user mode programs can be compiled in the kernel.

- Enabling of control flow integrity for user programs is left to user runtime

- This patch series introduces arch agnostic `prctls` to enable shadow stack
  and indirect branch tracking. And implements them on riscv.

---
Andy Chiu (1):
      riscv: signal: abstract header saving for setup_sigcontext

Clément Léger (1):
      riscv: Add Firmware Feature SBI extensions definitions

Deepak Gupta (26):
      mm: helper `is_shadow_stack_vma` to check shadow stack vma
      riscv/Kconfig: enable HAVE_EXIT_THREAD for riscv
      dt-bindings: riscv: zicfilp and zicfiss in dt-bindings (extensions.yaml)
      riscv: zicfiss / zicfilp enumeration
      riscv: zicfiss / zicfilp extension csr and bit definitions
      riscv: usercfi state for task and save/restore of CSR_SSP on trap entry/exit
      riscv/mm : ensure PROT_WRITE leads to VM_READ | VM_WRITE
      riscv mm: manufacture shadow stack pte
      riscv mmu: teach pte_mkwrite to manufacture shadow stack PTEs
      riscv mmu: write protect and shadow stack
      riscv/mm: Implement map_shadow_stack() syscall
      riscv/shstk: If needed allocate a new shadow stack on clone
      prctl: arch-agnostic prctl for indirect branch tracking
      riscv: Implements arch agnostic shadow stack prctls
      riscv: Implements arch agnostic indirect branch tracking prctls
      riscv/traps: Introduce software check exception
      riscv/signal: save and restore of shadow stack for signal
      riscv/kernel: update __show_regs to print shadow stack register
      riscv/ptrace: riscv cfi status and state via ptrace and in core files
      riscv/hwprobe: zicfilp / zicfiss enumeration in hwprobe
      riscv: enable kernel access to shadow stack memory via FWFT sbi call
      riscv: kernel command line option to opt out of user cfi
      riscv: create a config for shadow stack and landing pad instr support
      riscv: Documentation for landing pad / indirect branch tracking
      riscv: Documentation for shadow stack on riscv
      kselftest/riscv: kselftest for user mode cfi

Mark Brown (2):
      mm: Introduce ARCH_HAS_USER_SHADOW_STACK
      prctl: arch-agnostic prctl for shadow stack

Samuel Holland (3):
      riscv: Enable cbo.zero only when all harts support Zicboz
      riscv: Add support for per-thread envcfg CSR values
      riscv: Call riscv_user_isa_enable() only on the boot hart

 Documentation/arch/riscv/index.rst                 |   2 +
 Documentation/arch/riscv/zicfilp.rst               | 115 +++++
 Documentation/arch/riscv/zicfiss.rst               | 176 +++++++
 .../devicetree/bindings/riscv/extensions.yaml      |  14 +
 arch/riscv/Kconfig                                 |  21 +
 arch/riscv/include/asm/asm-prototypes.h            |   1 +
 arch/riscv/include/asm/cpufeature.h                |  15 +-
 arch/riscv/include/asm/csr.h                       |  16 +
 arch/riscv/include/asm/entry-common.h              |   2 +
 arch/riscv/include/asm/hwcap.h                     |   2 +
 arch/riscv/include/asm/mman.h                      |  24 +
 arch/riscv/include/asm/pgtable.h                   |  30 +-
 arch/riscv/include/asm/processor.h                 |   3 +
 arch/riscv/include/asm/sbi.h                       |  27 ++
 arch/riscv/include/asm/switch_to.h                 |   8 +
 arch/riscv/include/asm/thread_info.h               |   3 +
 arch/riscv/include/asm/usercfi.h                   |  89 ++++
 arch/riscv/include/asm/vector.h                    |   3 +
 arch/riscv/include/uapi/asm/hwprobe.h              |   2 +
 arch/riscv/include/uapi/asm/ptrace.h               |  22 +
 arch/riscv/include/uapi/asm/sigcontext.h           |   1 +
 arch/riscv/kernel/Makefile                         |   2 +
 arch/riscv/kernel/asm-offsets.c                    |   8 +
 arch/riscv/kernel/cpufeature.c                     |  13 +-
 arch/riscv/kernel/entry.S                          |  31 +-
 arch/riscv/kernel/head.S                           |  12 +
 arch/riscv/kernel/process.c                        |  31 +-
 arch/riscv/kernel/ptrace.c                         |  83 ++++
 arch/riscv/kernel/signal.c                         | 140 +++++-
 arch/riscv/kernel/smpboot.c                        |   2 -
 arch/riscv/kernel/suspend.c                        |   4 +-
 arch/riscv/kernel/sys_hwprobe.c                    |   2 +
 arch/riscv/kernel/sys_riscv.c                      |  10 +
 arch/riscv/kernel/traps.c                          |  42 ++
 arch/riscv/kernel/usercfi.c                        | 526 +++++++++++++++++++++
 arch/riscv/mm/init.c                               |   2 +-
 arch/riscv/mm/pgtable.c                            |  17 +
 arch/x86/Kconfig                                   |   1 +
 fs/proc/task_mmu.c                                 |   2 +-
 include/linux/cpu.h                                |   4 +
 include/linux/mm.h                                 |   5 +-
 include/uapi/asm-generic/mman.h                    |   4 +
 include/uapi/linux/elf.h                           |   1 +
 include/uapi/linux/prctl.h                         |  48 ++
 kernel/sys.c                                       |  60 +++
 mm/Kconfig                                         |   6 +
 mm/gup.c                                           |   2 +-
 mm/mmap.c                                          |   1 +
 mm/vma.h                                           |  10 +-
 tools/testing/selftests/riscv/Makefile             |   2 +-
 tools/testing/selftests/riscv/cfi/.gitignore       |   3 +
 tools/testing/selftests/riscv/cfi/Makefile         |  10 +
 tools/testing/selftests/riscv/cfi/cfi_rv_test.h    |  84 ++++
 tools/testing/selftests/riscv/cfi/riscv_cfi_test.c |  78 +++
 tools/testing/selftests/riscv/cfi/shadowstack.c    | 373 +++++++++++++++
 tools/testing/selftests/riscv/cfi/shadowstack.h    |  37 ++
 56 files changed, 2190 insertions(+), 42 deletions(-)
---
base-commit: 7d9923ee3960bdbfaa7f3a4e0ac2364e770c46ff
change-id: 20240930-v5_user_cfi_series-3dc332f8f5b2
--
- debug

Comments

Zong Li Oct. 11, 2024, 5:44 a.m. UTC | #1
On Wed, Oct 9, 2024 at 7:46 AM Deepak Gupta <debug@rivosinc.com> wrote:
>
> Adds kselftest for RISC-V control flow integrity implementation for user
> mode. There is not a lot going on in kernel for enabling landing pad for
> user mode. cfi selftest are intended to be compiled with zicfilp and
> zicfiss enabled compiler. Thus kselftest simply checks if landing pad and
> shadow stack for the binary and process are enabled or not. selftest then
> register a signal handler for SIGSEGV. Any control flow violation are
> reported as SIGSEGV with si_code = SEGV_CPERR. Test will fail on receiving
> any SEGV_CPERR. Shadow stack part has more changes in kernel and thus there
> are separate tests for that
>
> - Exercise `map_shadow_stack` syscall
> - `fork` test to make sure COW works for shadow stack pages
> - gup tests
>   Kernel uses FOLL_FORCE when access happens to memory via
>   /proc/<pid>/mem. Not breaking that for shadow stack.
> - signal test. Make sure signal delivery results in token creation on
>   shadow stack and consumes (and verifies) token on sigreturn
> - shadow stack protection test. attempts to write using regular store
>   instruction on shadow stack memory must result in access faults
>
> Test outut
> ==========
>
> """
> TAP version 13
> 1..5
>   This is to ensure shadow stack is indeed enabled and working
>   This is to ensure shadow stack is indeed enabled and working
> ok 1 shstk fork test
> ok 2 map shadow stack syscall
> ok 3 shadow stack gup tests
> ok 4 shadow stack signal tests
> ok 5 memory protections of shadow stack memory
> """
>
> Signed-off-by: Deepak Gupta <debug@rivosinc.com>
> ---
>  tools/testing/selftests/riscv/Makefile             |   2 +-
>  tools/testing/selftests/riscv/cfi/.gitignore       |   3 +
>  tools/testing/selftests/riscv/cfi/Makefile         |  10 +
>  tools/testing/selftests/riscv/cfi/cfi_rv_test.h    |  84 +++++
>  tools/testing/selftests/riscv/cfi/riscv_cfi_test.c |  78 +++++
>  tools/testing/selftests/riscv/cfi/shadowstack.c    | 373 +++++++++++++++++++++
>  tools/testing/selftests/riscv/cfi/shadowstack.h    |  37 ++
>  7 files changed, 586 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftests/riscv/Makefile
> index 7ce03d832b64..6e142fe004ab 100644
> --- a/tools/testing/selftests/riscv/Makefile
> +++ b/tools/testing/selftests/riscv/Makefile
> @@ -5,7 +5,7 @@
>  ARCH ?= $(shell uname -m 2>/dev/null || echo not)
>
>  ifneq (,$(filter $(ARCH),riscv))
> -RISCV_SUBTARGETS ?= hwprobe vector mm sigreturn
> +RISCV_SUBTARGETS ?= hwprobe vector mm sigreturn cfi
>  else
>  RISCV_SUBTARGETS :=
>  endif
> diff --git a/tools/testing/selftests/riscv/cfi/.gitignore b/tools/testing/selftests/riscv/cfi/.gitignore
> new file mode 100644
> index 000000000000..82545863bac6
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/cfi/.gitignore
> @@ -0,0 +1,3 @@
> +cfitests
> +riscv_cfi_test
> +shadowstack
> diff --git a/tools/testing/selftests/riscv/cfi/Makefile b/tools/testing/selftests/riscv/cfi/Makefile
> new file mode 100644
> index 000000000000..b65f7ff38a32
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/cfi/Makefile
> @@ -0,0 +1,10 @@
> +CFLAGS += -I$(top_srcdir)/tools/include
> +
> +CFLAGS += -march=rv64gc_zicfilp_zicfiss
> +
> +TEST_GEN_PROGS := cfitests
> +
> +include ../../lib.mk
> +
> +$(OUTPUT)/cfitests: riscv_cfi_test.c shadowstack.c
> +       $(CC) -o$@ $(CFLAGS) $(LDFLAGS) $^
> diff --git a/tools/testing/selftests/riscv/cfi/cfi_rv_test.h b/tools/testing/selftests/riscv/cfi/cfi_rv_test.h
> new file mode 100644
> index 000000000000..0fefdc33f71e
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/cfi/cfi_rv_test.h
> @@ -0,0 +1,84 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef SELFTEST_RISCV_CFI_H
> +#define SELFTEST_RISCV_CFI_H
> +#include <stddef.h>
> +#include <sys/types.h>
> +#include "shadowstack.h"
> +
> +#define RISCV_CFI_SELFTEST_COUNT RISCV_SHADOW_STACK_TESTS
> +
> +#define CHILD_EXIT_CODE_SSWRITE                10
> +#define CHILD_EXIT_CODE_SIG_TEST       11
> +
> +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                 \
> +({                                                                     \
> +       register long _num  __asm__ ("a7") = (num);                     \
> +       register long _arg1 __asm__ ("a0") = (long)(arg1);              \
> +       register long _arg2 __asm__ ("a1") = (long)(arg2);              \
> +       register long _arg3 __asm__ ("a2") = (long)(arg3);              \
> +       register long _arg4 __asm__ ("a3") = (long)(arg4);              \
> +       register long _arg5 __asm__ ("a4") = (long)(arg5);              \
> +                                                                       \
> +       __asm__ volatile(                                               \
> +               "ecall\n"                                               \
> +               : "+r"                                                  \
> +               (_arg1)                                                 \
> +               : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5),       \
> +                 "r"(_num)                                             \
> +               : "memory", "cc"                                        \
> +       );                                                              \
> +       _arg1;                                                          \
> +})
> +
> +#define my_syscall3(num, arg1, arg2, arg3)                             \
> +({                                                                     \
> +       register long _num  __asm__ ("a7") = (num);                     \
> +       register long _arg1 __asm__ ("a0") = (long)(arg1);              \
> +       register long _arg2 __asm__ ("a1") = (long)(arg2);              \
> +       register long _arg3 __asm__ ("a2") = (long)(arg3);              \
> +                                                                       \
> +       __asm__ volatile(                                               \
> +               "ecall\n"                                               \
> +               : "+r" (_arg1)                                          \
> +               : "r"(_arg2), "r"(_arg3),                               \
> +                 "r"(_num)                                             \
> +               : "memory", "cc"                                        \
> +       );                                                              \
> +       _arg1;                                                          \
> +})
> +
> +#ifndef __NR_prctl
> +#define __NR_prctl 167
> +#endif
> +
> +#ifndef __NR_map_shadow_stack
> +#define __NR_map_shadow_stack 453
> +#endif
> +
> +#define CSR_SSP 0x011
> +
> +#ifdef __ASSEMBLY__
> +#define __ASM_STR(x)    x
> +#else
> +#define __ASM_STR(x)    #x
> +#endif
> +
> +#define csr_read(csr)                                                  \
> +({                                                                     \
> +       register unsigned long __v;                                     \
> +       __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr)                \
> +                               : "=r" (__v) :                          \
> +                               : "memory");                            \
> +       __v;                                                            \
> +})
> +
> +#define csr_write(csr, val)                                            \
> +({                                                                     \
> +       unsigned long __v = (unsigned long) (val);                      \
> +       __asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0"             \
> +                               : : "rK" (__v)                          \
> +                               : "memory");                            \
> +})
> +
> +#endif
> diff --git a/tools/testing/selftests/riscv/cfi/riscv_cfi_test.c b/tools/testing/selftests/riscv/cfi/riscv_cfi_test.c
> new file mode 100644
> index 000000000000..720a001f7c31
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/cfi/riscv_cfi_test.c
> @@ -0,0 +1,78 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include "../../kselftest.h"
> +#include <signal.h>
> +#include <asm/ucontext.h>
> +#include <linux/prctl.h>
> +#include "cfi_rv_test.h"
> +
> +/* do not optimize cfi related test functions */
> +#pragma GCC push_options
> +#pragma GCC optimize("O0")
> +
> +void sigsegv_handler(int signum, siginfo_t *si, void *uc)
> +{
> +       struct ucontext *ctx = (struct ucontext *) uc;
> +
> +       if (si->si_code == SEGV_CPERR) {

Hi Deepak,
I got some errors when building this test, I suppose they should be
fixed in the next version.

riscv_cfi_test.c: In function 'sigsegv_handler':
riscv_cfi_test.c:17:28: error: 'SEGV_CPERR' undeclared (first use in
this function); did you mean 'SEGV_ACCERR'?
   17 |         if (si->si_code == SEGV_CPERR) {
      |                            ^~~~~~~~~~
      |                            SEGV_ACCERR


> +               ksft_print_msg("Control flow violation happened somewhere\n");
> +               ksft_print_msg("PC where violation happened %lx\n", ctx->uc_mcontext.gregs[0]);
> +               exit(-1);
> +       }
> +
> +       /* all other cases are expected to be of shadow stack write case */
> +       exit(CHILD_EXIT_CODE_SSWRITE);
> +}
> +
> +bool register_signal_handler(void)
> +{
> +       struct sigaction sa = {};
> +
> +       sa.sa_sigaction = sigsegv_handler;
> +       sa.sa_flags = SA_SIGINFO;
> +       if (sigaction(SIGSEGV, &sa, NULL)) {
> +               ksft_print_msg("Registering signal handler for landing pad violation failed\n");
> +               return false;
> +       }
> +
> +       return true;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +       int ret = 0;
> +       unsigned long lpad_status = 0, ss_status = 0;
> +
> +       ksft_print_header();
> +
> +       ksft_print_msg("Starting risc-v tests\n");
> +
> +       /*
> +        * Landing pad test. Not a lot of kernel changes to support landing
> +        * pad for user mode except lighting up a bit in senvcfg via a prctl
> +        * Enable landing pad through out the execution of test binary
> +        */
> +       ret = my_syscall5(__NR_prctl, PR_GET_INDIR_BR_LP_STATUS, &lpad_status, 0, 0, 0);
> +       if (ret)
> +               ksft_exit_fail_msg("Get landing pad status failed with %d\n", ret);
> +
> +       if (!(lpad_status & PR_INDIR_BR_LP_ENABLE))
> +               ksft_exit_fail_msg("Landing pad is not enabled, should be enabled via glibc\n");
> +
> +       ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0);
> +       if (ret)
> +               ksft_exit_fail_msg("Get shadow stack failed with %d\n", ret);
> +
> +       if (!(ss_status & PR_SHADOW_STACK_ENABLE))
> +               ksft_exit_fail_msg("Shadow stack is not enabled, should be enabled via glibc\n");
> +
> +       if (!register_signal_handler())
> +               ksft_exit_fail_msg("Registering signal handler for SIGSEGV failed\n");
> +
> +       ksft_print_msg("Landing pad and shadow stack are enabled for binary\n");
> +       execute_shadow_stack_tests();
> +
> +       return 0;
> +}
> +
> +#pragma GCC pop_options
> diff --git a/tools/testing/selftests/riscv/cfi/shadowstack.c b/tools/testing/selftests/riscv/cfi/shadowstack.c
> new file mode 100644
> index 000000000000..9d5301914578
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/cfi/shadowstack.c
> @@ -0,0 +1,373 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include "../../kselftest.h"
> +#include <sys/wait.h>
> +#include <signal.h>
> +#include <fcntl.h>
> +#include <asm-generic/unistd.h>
> +#include <sys/mman.h>
> +#include "shadowstack.h"
> +#include "cfi_rv_test.h"
> +
> +/* do not optimize shadow stack related test functions */
> +#pragma GCC push_options
> +#pragma GCC optimize("O0")
> +
> +void zar(void)
> +{
> +       unsigned long ssp = 0;
> +
> +       ssp = csr_read(CSR_SSP);
> +       ksft_print_msg("Spewing out shadow stack ptr: %lx\n"
> +                       "  This is to ensure shadow stack is indeed enabled and working\n",
> +                       ssp);
> +}
> +
> +void bar(void)
> +{
> +       zar();
> +}
> +
> +void foo(void)
> +{
> +       bar();
> +}
> +
> +void zar_child(void)
> +{
> +       unsigned long ssp = 0;
> +
> +       ssp = csr_read(CSR_SSP);
> +       ksft_print_msg("Spewing out shadow stack ptr: %lx\n"
> +                       "  This is to ensure shadow stack is indeed enabled and working\n",
> +                       ssp);
> +}
> +
> +void bar_child(void)
> +{
> +       zar_child();
> +}
> +
> +void foo_child(void)
> +{
> +       bar_child();
> +}
> +
> +typedef void (call_func_ptr)(void);
> +/*
> + * call couple of functions to test push pop.
> + */
> +int shadow_stack_call_tests(call_func_ptr fn_ptr, bool parent)
> +{
> +       ksft_print_msg("Exercising dummy calls for sspush and sspopchk in"
> +                       " context of %s\n", parent ? "parent" : "child");
> +
> +       (fn_ptr)();
> +
> +       return 0;
> +}
> +
> +/* forks a thread, and ensure shadow stacks fork out */
> +bool shadow_stack_fork_test(unsigned long test_num, void *ctx)
> +{
> +       int pid = 0, child_status = 0, parent_pid = 0, ret = 0;
> +       unsigned long ss_status = 0;
> +
> +       ksft_print_msg("Exercising shadow stack fork test\n");
> +
> +       ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0);
> +       if (ret) {
> +               ksft_exit_skip("Shadow stack get status prctl failed with errorcode %d\n", ret);
> +               return false;
> +       }
> +
> +       if (!(ss_status & PR_SHADOW_STACK_ENABLE))
> +               ksft_exit_skip("Shadow stack is not enabled, should be enabled via glibc\n");
> +
> +       parent_pid = getpid();
> +       pid = fork();
> +
> +       if (pid) {
> +               ksft_print_msg("Parent pid %d and child pid %d\n", parent_pid, pid);
> +               shadow_stack_call_tests(&foo, true);
> +       } else
> +               shadow_stack_call_tests(&foo_child, false);
> +
> +       if (pid) {
> +               ksft_print_msg("Waiting on child to finish\n");
> +               wait(&child_status);
> +       } else {
> +               /* exit child gracefully */
> +               exit(0);
> +       }
> +
> +       if (pid && WIFSIGNALED(child_status)) {
> +               ksft_print_msg("Child faulted, fork test failed\n");
> +               return false;
> +       }
> +
> +       return true;
> +}
> +
> +/* exercise `map_shadow_stack`, pivot to it and call some functions to ensure it works */
> +#define SHADOW_STACK_ALLOC_SIZE 4096
> +bool shadow_stack_map_test(unsigned long test_num, void *ctx)
> +{
> +       unsigned long shdw_addr;
> +       int ret = 0;
> +
> +       ksft_print_msg("Exercising shadow stack map test\n");
> +
> +       shdw_addr = my_syscall3(__NR_map_shadow_stack, NULL, SHADOW_STACK_ALLOC_SIZE, 0);
> +
> +       if (((long) shdw_addr) <= 0) {
> +               ksft_print_msg("map_shadow_stack failed with error code %d\n", (int) shdw_addr);
> +               return false;
> +       }
> +
> +       ret = munmap((void *) shdw_addr, SHADOW_STACK_ALLOC_SIZE);
> +
> +       if (ret) {
> +               ksft_print_msg("munmap failed with error code %d\n", ret);
> +               return false;
> +       }
> +
> +       return true;
> +}
> +
> +/*
> + * shadow stack protection tests. map a shadow stack and
> + * validate all memory protections work on it
> + */
> +bool shadow_stack_protection_test(unsigned long test_num, void *ctx)
> +{
> +       unsigned long shdw_addr;
> +       unsigned long *write_addr = NULL;
> +       int ret = 0, pid = 0, child_status = 0;
> +
> +       ksft_print_msg("Exercising shadow stack protection test\n");
> +
> +       shdw_addr = my_syscall3(__NR_map_shadow_stack, NULL, SHADOW_STACK_ALLOC_SIZE, 0);
> +
> +       if (((long) shdw_addr) <= 0) {
> +               ksft_print_msg("map_shadow_stack failed with error code %d\n", (int) shdw_addr);
> +               return false;
> +       }
> +
> +       write_addr = (unsigned long *) shdw_addr;
> +       pid = fork();
> +
> +       /* no child was created, return false */
> +       if (pid == -1)
> +               return false;
> +
> +       /*
> +        * try to perform a store from child on shadow stack memory
> +        * it should result in SIGSEGV
> +        */
> +       if (!pid) {
> +               /* below write must lead to SIGSEGV */
> +               *write_addr = 0xdeadbeef;
> +       } else {
> +               wait(&child_status);
> +       }
> +
> +       /* test fail, if 0xdeadbeef present on shadow stack address */
> +       if (*write_addr == 0xdeadbeef) {
> +               ksft_print_msg("Write suceeded on shadow stack memory, shadow stack protection test"
> +               " failed\n");
> +               return false;
> +       }
> +
> +       /* if child reached here, then fail */
> +       if (!pid) {
> +               ksft_print_msg("Shadow stack protection test: child reached unreachable state\n");
> +               return false;
> +       }
> +
> +       /* if child exited via signal handler but not for write on ss */
> +       if (WIFEXITED(child_status) &&
> +               WEXITSTATUS(child_status) != CHILD_EXIT_CODE_SSWRITE) {
> +               ksft_print_msg("Shadow stack protection test: child wasn't signaled for write on"
> +               " shadow stack\n");
> +               return false;
> +       }
> +
> +       ret = munmap(write_addr, SHADOW_STACK_ALLOC_SIZE);
> +       if (ret) {
> +               ksft_print_msg("Shadow stack protection test: munmap failed with error code %d\n",
> +               ret);
> +               return false;
> +       }
> +
> +       return true;
> +}
> +
> +#define SS_MAGIC_WRITE_VAL 0xbeefdead
> +
> +int gup_tests(int mem_fd, unsigned long *shdw_addr)
> +{
> +       unsigned long val = 0;
> +
> +       lseek(mem_fd, (unsigned long)shdw_addr, SEEK_SET);
> +       if (read(mem_fd, &val, sizeof(val)) < 0) {
> +               ksft_print_msg("Reading shadow stack mem via gup failed\n");
> +               return 1;
> +       }
> +
> +       val = SS_MAGIC_WRITE_VAL;
> +       lseek(mem_fd, (unsigned long)shdw_addr, SEEK_SET);
> +       if (write(mem_fd, &val, sizeof(val)) < 0) {
> +               ksft_print_msg("Writing shadow stack mem via gup failed\n");
> +               return 1;
> +       }
> +
> +       if (*shdw_addr != SS_MAGIC_WRITE_VAL) {
> +               ksft_print_msg("GUP write to shadow stack memory failed\n");
> +               return 1;
> +       }
> +
> +       return 0;
> +}
> +
> +bool shadow_stack_gup_tests(unsigned long test_num, void *ctx)
> +{
> +       unsigned long shdw_addr = 0;
> +       unsigned long *write_addr = NULL;
> +       int fd = 0;
> +       bool ret = false;
> +
> +       ksft_print_msg("Exercising shadow stack gup tests\n");
> +       shdw_addr = my_syscall3(__NR_map_shadow_stack, NULL, SHADOW_STACK_ALLOC_SIZE, 0);
> +
> +       if (((long) shdw_addr) <= 0) {
> +               ksft_print_msg("map_shadow_stack failed with error code %d\n", (int) shdw_addr);
> +               return false;
> +       }
> +
> +       write_addr = (unsigned long *) shdw_addr;
> +
> +       fd = open("/proc/self/mem", O_RDWR);
> +       if (fd == -1)
> +               return false;
> +
> +       if (gup_tests(fd, write_addr)) {
> +               ksft_print_msg("gup tests failed\n");
> +               goto out;
> +       }
> +
> +       ret = true;
> +out:
> +       if (shdw_addr && munmap(write_addr, SHADOW_STACK_ALLOC_SIZE)) {
> +               ksft_print_msg("munmap failed with error code %d\n", ret);
> +               ret = false;
> +       }
> +
> +       return ret;
> +}
> +
> +volatile bool break_loop;
> +
> +void sigusr1_handler(int signo)
> +{
> +       break_loop = true;
> +}
> +
> +bool sigusr1_signal_test(void)
> +{
> +       struct sigaction sa = {};
> +
> +       sa.sa_handler = sigusr1_handler;
> +       sa.sa_flags = 0;
> +       sigemptyset(&sa.sa_mask);
> +       if (sigaction(SIGUSR1, &sa, NULL)) {
> +               ksft_print_msg("Registering signal handler for SIGUSR1 failed\n");
> +               return false;
> +       }
> +
> +       return true;
> +}
> +/*
> + * shadow stack signal test. shadow stack must be enabled.
> + * register a signal, fork another thread which is waiting
> + * on signal. Send a signal from parent to child, verify
> + * that signal was received by child. If not test fails
> + */
> +bool shadow_stack_signal_test(unsigned long test_num, void *ctx)
> +{
> +       int pid = 0, child_status = 0, ret = 0;
> +       unsigned long ss_status = 0;
> +
> +       ksft_print_msg("Exercising shadow stack signal test\n");
> +
> +       ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0);
> +       if (ret) {
> +               ksft_print_msg("Shadow stack get status prctl failed with errorcode %d\n", ret);
> +               return false;
> +       }
> +
> +       if (!(ss_status & PR_SHADOW_STACK_ENABLE))
> +               ksft_print_msg("Shadow stack is not enabled, should be enabled via glibc\n");
> +
> +       /* this should be caught by signal handler and do an exit */
> +       if (!sigusr1_signal_test()) {
> +               ksft_print_msg("Registering sigusr1 handler failed\n");
> +               exit(-1);
> +       }
> +
> +       pid = fork();
> +
> +       if (pid == -1) {
> +               ksft_print_msg("Signal test: fork failed\n");
> +               goto out;
> +       }
> +
> +       if (pid == 0) {
> +               while (!break_loop)
> +                       sleep(1);
> +
> +               exit(11);
> +               /* child shouldn't go beyond here */
> +       }
> +
> +       /* send SIGUSR1 to child */
> +       kill(pid, SIGUSR1);
> +       wait(&child_status);
> +
> +out:
> +
> +       return (WIFEXITED(child_status) &&
> +                       WEXITSTATUS(child_status) == 11);
> +}
> +
> +int execute_shadow_stack_tests(void)
> +{
> +       int ret = 0;
> +       unsigned long test_count = 0;
> +       unsigned long shstk_status = 0;
> +       bool test_pass = false;
> +
> +       ksft_print_msg("Executing RISC-V shadow stack self tests\n");
> +       ksft_set_plan(RISCV_SHADOW_STACK_TESTS);
> +
> +       ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &shstk_status, 0, 0, 0);
> +
> +       if (ret != 0)
> +               ksft_exit_fail_msg("Get shadow stack status failed with %d\n", ret);
> +
> +       /*
> +        * If we are here that means get shadow stack status succeeded and
> +        * thus shadow stack support is baked in the kernel.
> +        */
> +       while (test_count < ARRAY_SIZE(shstk_tests)) {
> +               test_pass = (*shstk_tests[test_count].t_func)(test_count, NULL);
> +               ksft_test_result(test_pass, shstk_tests[test_count].name);
> +               test_count++;
> +       }
> +
> +       ksft_finished();
> +
> +       return 0;
> +}
> +
> +#pragma GCC pop_options
> diff --git a/tools/testing/selftests/riscv/cfi/shadowstack.h b/tools/testing/selftests/riscv/cfi/shadowstack.h
> new file mode 100644
> index 000000000000..b43e74136a26
> --- /dev/null
> +++ b/tools/testing/selftests/riscv/cfi/shadowstack.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef SELFTEST_SHADOWSTACK_TEST_H
> +#define SELFTEST_SHADOWSTACK_TEST_H
> +#include <stddef.h>
> +#include <linux/prctl.h>
> +
> +/*
> + * a cfi test returns true for success or false for fail
> + * takes a number for test number to index into array and void pointer.
> + */
> +typedef bool (*shstk_test_func)(unsigned long test_num, void *);
> +
> +struct shadow_stack_tests {
> +       char *name;
> +       shstk_test_func t_func;
> +};
> +
> +bool shadow_stack_fork_test(unsigned long test_num, void *ctx);
> +bool shadow_stack_map_test(unsigned long test_num, void *ctx);
> +bool shadow_stack_protection_test(unsigned long test_num, void *ctx);
> +bool shadow_stack_gup_tests(unsigned long test_num, void *ctx);
> +bool shadow_stack_signal_test(unsigned long test_num, void *ctx);
> +
> +static struct shadow_stack_tests shstk_tests[] = {

shadowstack.h:25:34: warning: 'shstk_tests' defined but not used
[-Wunused-variable]
   25 | static struct shadow_stack_tests shstk_tests[] = {

> +       { "shstk fork test\n", shadow_stack_fork_test },
> +       { "map shadow stack syscall\n", shadow_stack_map_test },
> +       { "shadow stack gup tests\n", shadow_stack_gup_tests },
> +       { "shadow stack signal tests\n", shadow_stack_signal_test},
> +       { "memory protections of shadow stack memory\n", shadow_stack_protection_test }
> +};
> +
> +#define RISCV_SHADOW_STACK_TESTS ARRAY_SIZE(shstk_tests)
> +
> +int execute_shadow_stack_tests(void);
> +
> +#endif
>
> --
> 2.45.0
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
Zong Li Oct. 11, 2024, 11:43 a.m. UTC | #2
On Fri, Oct 11, 2024 at 6:18 PM Mark Brown <broonie@kernel.org> wrote:
>
> On Fri, Oct 11, 2024 at 01:44:55PM +0800, Zong Li wrote:
> > On Wed, Oct 9, 2024 at 7:46 AM Deepak Gupta <debug@rivosinc.com> wrote:
>
> > > +       if (si->si_code == SEGV_CPERR) {
>
> > Hi Deepak,
> > I got some errors when building this test, I suppose they should be
> > fixed in the next version.
>
> > riscv_cfi_test.c: In function 'sigsegv_handler':
> > riscv_cfi_test.c:17:28: error: 'SEGV_CPERR' undeclared (first use in
> > this function); did you mean 'SEGV_ACCERR'?
> >    17 |         if (si->si_code == SEGV_CPERR) {
> >       |                            ^~~~~~~~~~
> >       |                            SEGV_ACCERR
> >
>
> Did you run "make headers_install" prior to building kselftest to get
> the current kernel's headers available for userspace builds?

Yes, I have run "make header" and "make header_install" before
building the kselftest. This error happens when I cross compiled it,
perhaps I can help to check if it is missing some header files or
header search path.
Zong Li Oct. 14, 2024, 2:33 p.m. UTC | #3
On Sat, Oct 12, 2024 at 3:46 AM Deepak Gupta <debug@rivosinc.com> wrote:
>
> On Fri, Oct 11, 2024 at 07:43:30PM +0800, Zong Li wrote:
> >On Fri, Oct 11, 2024 at 6:18 PM Mark Brown <broonie@kernel.org> wrote:
> >>
> >> On Fri, Oct 11, 2024 at 01:44:55PM +0800, Zong Li wrote:
> >> > On Wed, Oct 9, 2024 at 7:46 AM Deepak Gupta <debug@rivosinc.com> wrote:
> >>
> >> > > +       if (si->si_code == SEGV_CPERR) {
> >>
> >> > Hi Deepak,
> >> > I got some errors when building this test, I suppose they should be
> >> > fixed in the next version.
> >>
> >> > riscv_cfi_test.c: In function 'sigsegv_handler':
> >> > riscv_cfi_test.c:17:28: error: 'SEGV_CPERR' undeclared (first use in
> >> > this function); did you mean 'SEGV_ACCERR'?
> >> >    17 |         if (si->si_code == SEGV_CPERR) {
> >> >       |                            ^~~~~~~~~~
> >> >       |                            SEGV_ACCERR
> >> >
> >>
> >> Did you run "make headers_install" prior to building kselftest to get
> >> the current kernel's headers available for userspace builds?
> >
> >Yes, I have run "make header" and "make header_install" before
> >building the kselftest. This error happens when I cross compiled it,
> >perhaps I can help to check if it is missing some header files or
> >header search path.
>
> That's wierd.
>
> It doesn't fail for me even if I do not do `make headers_install`. But I am
> building kernel and selftests with toolchain which supports shadow stack and
> landing pad. It's defined in `siginfo.h`. When I built toolchain, I did point
> it at the latest kernel headers. May be that's the trick.
>
> """
>
> $ grep -nir SEGV_CPERR /scratch/debug/linux/kbuild/usr/include/*
> /scratch/debug/linux/kbuild/usr/include/asm-generic/siginfo.h:240:#define SEGV_CPERR    10      /* Control protection fault */
>
> $ grep -nir SEGV_CPERR /scratch/debug/open_src/sifive_cfi_toolchain/INSTALL_Sept18/sysroot/usr/*
> /scratch/debug/open_src/sifive_cfi_toolchain/INSTALL_Sept18/sysroot/usr/include/asm-generic/siginfo.h:240:#define SEGV_CPERR    10      /* Control protection fault */
> /scratch/debug/open_src/sifive_cfi_toolchain/INSTALL_Sept18/sysroot/usr/include/bits/siginfo-consts.h:139:  SEGV_CPERR                  /* Control protection fault.  */
> /scratch/debug/open_src/sifive_cfi_toolchain/INSTALL_Sept18/sysroot/usr/include/bits/siginfo-consts.h:140:#  define SEGV_CPERR  SEGV_CPERR
>
> """

In my case, because the test files don't explicitly include siginfo.h,
I assume it's expected that siginfo.h will be included through
signal.h. Regarding the header search path, it will eventually locate
signal.h in toolchain_path/sysroot/usr/include/. In my
toolchain_path/sysroot/usr/include/signal.h, it doesn't include any
signal.h; instead, signal.h will be included from
toolchain_path/sysroot/usr/include/linux/signal.h or
kernel_src/usr/include/linux/signal.h rather than
toolchain/sysroot/usr/include/signal.h. I think that is why I lost the
SEGV_CPERR definition. Is there any difference with you?

>
Rob Herring Oct. 25, 2024, 9:58 p.m. UTC | #4
On Tue, 08 Oct 2024 15:36:49 -0700, Deepak Gupta wrote:
> Make an entry for cfi extensions in extensions.yaml.
> 
> Signed-off-by: Deepak Gupta <debug@rivosinc.com>
> ---
>  Documentation/devicetree/bindings/riscv/extensions.yaml | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 

Acked-by: Rob Herring (Arm) <robh@kernel.org>