CT_01_003 - Shadow Stacks (LLVM)
About
Shadow stacks are a security feature meant to detect/prevent classes of attacks where a malicious actor has gained control over a function's return pointer. Shadow stack mechanisms typically need a combination of compiler, library, dynamic loader and kernel support, they often require special support for JITs as well. This work item is only tracking the core LLVM functionality needed to support shadow stacks. Shadow stacks are seen as a blocking issue for Android on RISC-V.
Stakeholders/Partners
RISE:
Ventana: Coordination with GCC community
Google: FTE driving implementation work
Mediatek: FTE driving implementation work
External:
Alex Bradbury:
Dependencies
The most pressing upstream dependencies are:
- PSABI specification to allow turning x3 into an OS defined register (rather than forcing it to be a global data pointer)
- Kernel and library support to enable shadow stack feature, library support to facilitate routines such as longjmp or unwinding which inherently need to pop values off the shadow stack
- Linker and dynamic loader support to either prevent mixing and matching of shadow stack aware code with non-aware code, or thunks between the domains to turn shadow stacks on/off.
- QEMU and/or Spike support for Zicfisslp
Status
Updates
- A PR for Spike with Zicfiss v0.4.0 support has been submitted: https://github.com/riscv-software-src/riscv-isa-sim/pull/1560
- As Zicfiss extension has passed architectural review, we will bump the Zicfiss version to v0.4.0, the latest and stable version, for glibc/setjmp and Spike.
- Preparing patches for upstreaming. This includes polishing the patches and adding tests. We will also bump to the latest spec version after Zicfiss gets ratified.
- One missing piece is Spike pk support to read the ELF flag of executables and enable shadow stack protection accordingly. We will also work on that later.
- Implemented the linking policy for Zicfiss and Zicfilp in LLD. The draft can be found here: https://github.com/SuHo-llrr/llvm-project/pull/1/commits
The patch set also includes the emission of ELF .note.gnu.property section and llvm-readobj changes to display the content of the section.
Since there are ongoing discussions on the linking policy, we will update the implementation when the decision is made.
Besides, we will also add test cases for upstreaming.
- Working on adding linking policy for Zicfiss in lld. We will align binutils implementation by SiFive (Thank Kito and Hau for the reference implementation).
To implement the linking policy, it requires feature information recorded in the .note.gnu.property section. Thank Kito again for the ABI spec.
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/commit/7367425eee8f36bf204ce86d90db7002b5de1e6c
- Implemented a glibc PoC to support setjmp/longjmp for Zicfiss v0.3.1.
The patch can be downloaded for evaluation and review here: https://github.com/bminor/glibc/commit/987dc1ac9ce9dc6776723391c231ed49e36e2e4e
To evaluate the patch, one can build glibc with CFLAGS+="-march=rv64gcv_zicfiss0p3 -menable-experimental-extensions".
This patch has passed validation, and those 6 runtime failures due to lack of setjmp/longjmp support have been fixed.
Further improvement and refactoring for this patch is required for upstreaming.
- A Spike PR, which implements a Zicfiss v0.3.1 instruction subset, was posted for review by Su-Hsien (MediaTek).
The purpose of the PR is to enable compiler validation and collect feedback. PR: https://github.com/riscv-software-src/riscv-isa-sim/pull/1475 - We have implemented setjmp/longjmp in glibc for Zicfiss. Validation is ongoing. It may require refactoring for upstreaming.
- glibc study to support setjmp/longjmp for Zicfiss is ongoing. It looks that there are many system-related details to consider.
- Update upstream and community activities related to Zicfiss:
- Spike PR for Zimop and Zcmop, which Zicfiss depends on, have been submitted by Ved (Rivos):
https://github.com/riscv-software-src/riscv-isa-sim/pull/1467
https://github.com/riscv-software-src/riscv-isa-sim/pull/1468 - The best place to put the flag for objects compiled with Zicfiss on was discussed by the psABI group. Thank you, Kito (SiFive) and psABI group!
We will implement this in LLVM when the final decision is made.
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/395 - LLVM PR for Zicfiss v0.3.1 is posted by Yeting (SiFive). Thank Yeting again!
https://github.com/llvm/llvm-project/pull/68075
https://github.com/llvm/llvm-project/pull/66043
- Spike PR for Zimop and Zcmop, which Zicfiss depends on, have been submitted by Ved (Rivos):
- The investigation on the 6 run failures is done. It turns out they are not Oz-specific failures, i.e. these 6 test cases failed for all optimization levels but our error reporting mechanism didn't catch the failures because we only checked the "passed" output string but didn't check shadow stack fault. We've fixed the error reporting system.
The root cause of the shadow stack fault on the 6 test cases is due to a lack of setjmp/longjmp support to save and restore shadow stack pointer. - We will study glibc and try to add the support. We will also add Zicfiss instructions that are required by setjmp/longjmp into Spike for validation purpose, such as ssrdp, ssld, etc.
An example glibc patch for x86 shadow stack can be found here: https://github.com/bminor/glibc/commit/faaee1f07ed25b2779bfd935ffb29f431b80d6d3
ABI discussions on jmp_buf can be found here: https://github.com/riscv/riscv-cfi/issues/142
- Two essential LLVM patches that implement Zicfiss v0.2 have been posted for review by fakepaper56 (thumbs up). We have validated these patches using Spike with newly added Zicfiss v0.3.1 instructions. It only requires slight encoding adjustment to run the validation. The validation results look good. There are only 6 run fails with -Oz for total 80K test programs. We will investigate these run fails.
https://reviews.llvm.org/D152793
https://reviews.llvm.org/D156549
- Built up a compiler validation environment based on Spike, on which we can run 13K C/C++ test cases with various optimization levels (O0, O1, O2, O3, Os, and Oz). The combinations (13K test cases x 6 optimization levels) will be sufficient for validating LLVM Zicfiss implementation.
- Successfully added sspush and sspopchk instruction into Spike. Although there are more instructions to be added (ssload, sspinc, etc), the current implementation already enables us to run most of the compiler tests with Zicfiss enabled. The next step will be building up a test environment for running commercial testsuites on Spike to obtain the original pass rate without Zicfiss enabled.
- Discussing a Zicfiss support proposal with Google. Will probably implement the Zicfiss extension in Spike as well to facilitate compiler validation and avoid the dependencies on QEMU, Linux kernel, and dynamic loaders.
- Update the current status, dependencies, and work that needs to be done for Zicfisslp shadow stacks. Please refer to the following spreadsheet for details. Since this is based on my recent study, if there is anything missing or incorrect, please kindly let me know. I (Chibang) will reach out to Google and Rivos to discuss opportunities for collaboration.
https://docs.google.com/spreadsheets/d/e/2PACX-1vSMW-7hBC6omqsZDLqxU4mCiZF313IEMoNRktrgE0QErfJjKaVfDOTOLlGZThpiEK2YCKIhTpBfF4y9/pubhtml?gid=0&single=true
- Consensus forming that x3 can be repurposed as an OS specific register
– Dates on or before June 1 are approximate
- Project reported as priority for 2H23