From fc8f53038be8938ae5b1b31d8d1944f5062d7d33 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sun, 21 Apr 2024 13:44:54 +0200 Subject: [PATCH 1/4] Fix make_fcontext/jump_fcontext with SHSTK enabled Sync Zend/asm/*_x86_64_sysv_elf_gas.S with upstream --- Zend/asm/jump_x86_64_sysv_elf_gas.S | 8 -------- Zend/asm/make_x86_64_sysv_elf_gas.S | 29 ----------------------------- 2 files changed, 37 deletions(-) diff --git a/Zend/asm/jump_x86_64_sysv_elf_gas.S b/Zend/asm/jump_x86_64_sysv_elf_gas.S index 40f8734daeeb1..703931cb0c26a 100644 --- a/Zend/asm/jump_x86_64_sysv_elf_gas.S +++ b/Zend/asm/jump_x86_64_sysv_elf_gas.S @@ -64,14 +64,6 @@ jump_fcontext: movq %rbx, 0x30(%rsp) /* save RBX */ movq %rbp, 0x38(%rsp) /* save RBP */ -#if BOOST_CONTEXT_SHADOW_STACK - /* grow the stack to reserve space for shadow stack pointer(SSP) */ - leaq -0x8(%rsp), %rsp - /* read the current SSP and store it */ - rdsspq %rcx - movq %rcx, (%rsp) -#endif - #if BOOST_CONTEXT_SHADOW_STACK /* grow the stack to reserve space for shadow stack pointer(SSP) */ leaq -0x8(%rsp), %rsp diff --git a/Zend/asm/make_x86_64_sysv_elf_gas.S b/Zend/asm/make_x86_64_sysv_elf_gas.S index 3358a27d844df..8c57a6793865c 100644 --- a/Zend/asm/make_x86_64_sysv_elf_gas.S +++ b/Zend/asm/make_x86_64_sysv_elf_gas.S @@ -88,35 +88,6 @@ make_fcontext: /* will be entered after context-function returns */ movq %rcx, 0x38(%rax) -#if BOOST_CONTEXT_SHADOW_STACK - /* Populate the shadow stack and normal stack */ - /* get original SSP */ - rdsspq %r8 - /* restore new shadow stack */ - rstorssp -0x8(%r9) - /* save the restore token on the original shadow stack */ - saveprevssp - /* push the address of "jmp trampoline" to the new shadow stack */ - /* as well as the stack */ - call 1f - jmp trampoline -1: - /* save address of "jmp trampoline" as return-address */ - /* for context-function */ - pop 0x38(%rax) - /* Get the new SSP. */ - rdsspq %r9 - /* restore original shadow stack */ - rstorssp -0x8(%r8) - /* save the restore token on the new shadow stack. */ - saveprevssp - - /* reserve space for the new SSP */ - leaq -0x8(%rax), %rax - /* save the new SSP to this fcontext */ - movq %r9, (%rax) -#endif - #if BOOST_CONTEXT_SHADOW_STACK /* Populate the shadow stack */ From 5a94da0437654395f3efae60a90b155bd60ab092 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sun, 21 Apr 2024 13:46:54 +0200 Subject: [PATCH 2/4] Fix map_shadow_stack syscall number * Syscall number for map_shadow_stack has changed since initial support was added. * Use SYS_map_shadow_stack instead of hard-coded number when possible --- Zend/zend_fibers.c | 8 ++++++-- configure.ac | 11 +++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index 6b6c1eaae1a96..a62b1683cc815 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -69,10 +69,14 @@ #endif # if defined __CET__ +# include +# include # include # define SHSTK_ENABLED (__CET__ & 0x2) # define BOOST_CONTEXT_SHADOW_STACK (SHSTK_ENABLED && SHADOW_STACK_SYSCALL) -# define __NR_map_shadow_stack 451 +# ifndef SYS_map_shadow_stack +# define SYS_map_shadow_stack 453 +# endif # ifndef SHADOW_STACK_SET_TOKEN # define SHADOW_STACK_SET_TOKEN 0x1 #endif @@ -272,7 +276,7 @@ static zend_fiber_stack *zend_fiber_stack_allocate(size_t size) /* issue syscall to create shadow stack for the new fcontext */ /* SHADOW_STACK_SET_TOKEN option will put "restore token" on the new shadow stack */ - stack->ss_base = (void *)syscall(__NR_map_shadow_stack, 0, stack->ss_size, SHADOW_STACK_SET_TOKEN); + stack->ss_base = (void *)syscall(SYS_map_shadow_stack, 0, stack->ss_size, SHADOW_STACK_SET_TOKEN); if (stack->ss_base == MAP_FAILED) { zend_throw_exception_ex(NULL, 0, "Fiber shadow stack allocate failed: mmap failed: %s (%d)", strerror(errno), errno); diff --git a/configure.ac b/configure.ac index 8784bbf088538..adb4ee0b073a3 100644 --- a/configure.ac +++ b/configure.ac @@ -1331,11 +1331,18 @@ fi dnl Check whether syscall to create shadow stack exists, should be a better way, but... AC_CACHE_CHECK([whether syscall to create shadow stack exists], ac_cv_syscall_shadow_stack_exists, [AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include #include #include +#ifndef SYS_map_shadow_stack +# define SYS_map_shadow_stack 453 +#endif +#ifndef SHADOW_STACK_SET_TOKEN +# define SHADOW_STACK_SET_TOKEN 0x1 +#endif int main(void) { - /* test if syscall 451, i.e., map_shadow_stack is available */ - void* base = (void *)syscall(451, 0, 0x20000, 0x1); + /* test if map_shadow_stack is available */ + void* base = (void *)syscall(SYS_map_shadow_stack, 0, 0x20000, SHADOW_STACK_SET_TOKEN); if (base != (void*)-1) { munmap(base, 0x20000); return 0; From 5c724e26b8af8cd5960090d7bed092a834ad20f7 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sun, 21 Apr 2024 13:48:22 +0200 Subject: [PATCH 3/4] Increase SHSTK stack size The shadow stack may need as much space as the fiber stack in the worse case, so allocate a shadow stack the same size as the fiber stack. This matches what the kernel does for the main stack. --- Zend/zend_fibers.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index a62b1683cc815..f9941fc5c9d9e 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -268,11 +268,7 @@ static zend_fiber_stack *zend_fiber_stack_allocate(size_t size) stack->size = stack_size; #if !defined(ZEND_FIBER_UCONTEXT) && BOOST_CONTEXT_SHADOW_STACK - /* shadow stack saves ret address only, need less space */ - stack->ss_size= stack_size >> 5; - - /* align shadow stack to 8 bytes. */ - stack->ss_size = (stack->ss_size + 7) & ~7; + stack->ss_size = stack_size; /* issue syscall to create shadow stack for the new fcontext */ /* SHADOW_STACK_SET_TOKEN option will put "restore token" on the new shadow stack */ From 47ddf5023192f8937612d42f9e4ab458a8be0f5f Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sun, 21 Apr 2024 13:58:47 +0200 Subject: [PATCH 4/4] Enable SHSTK in CI --- .github/workflows/nightly.yml | 6 +++++- .github/workflows/push.yml | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a487ce61bba8d..cd6fe53bea79e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -59,7 +59,7 @@ jobs: fail-fast: false matrix: branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }} - configuration_parameters: [''] + configuration_parameters: ['CFLAGS="-fcf-protection=full" LDFLAGS="-Wl,-z,cet-report=error"'] debug: [true, false] name: [''] run_tests_parameters: [''] @@ -112,12 +112,16 @@ jobs: uses: ./.github/actions/setup-x64 - name: Test uses: ./.github/actions/test-linux + env: + GLIBC_TUNABLES: 'glibc.cpu.hwcaps=SHSTK' with: runTestsParameters: >- ${{ matrix.run_tests_parameters }} idleCpu: ${{ matrix.asan && 'true' || 'false' }} - name: Test Tracing JIT uses: ./.github/actions/test-linux + env: + GLIBC_TUNABLES: 'glibc.cpu.hwcaps=SHSTK' with: jitType: tracing runTestsParameters: >- diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 6edba327f57bb..5cdf7cf41bba0 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -110,7 +110,7 @@ jobs: configurationParameters: >- --${{ matrix.debug && 'enable' || 'disable' }}-debug --${{ matrix.zts && 'enable' || 'disable' }}-zts - ${{ matrix.asan && 'CFLAGS="-fsanitize=undefined,address -fno-sanitize=function -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address -fno-sanitize=function" CC=clang CXX=clang++ --disable-opcache-jit' || '' }} + ${{ matrix.asan && 'CFLAGS="-fsanitize=undefined,address -fno-sanitize=function -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address -fno-sanitize=function" CC=clang CXX=clang++ --disable-opcache-jit' || 'CFLAGS="-fcf-protection=full" LDFLAGS="-Wl,-z,cet-report=error"' }} skipSlow: ${{ matrix.asan }} - name: make run: make -j$(/usr/bin/nproc) >/dev/null @@ -123,6 +123,8 @@ jobs: if: matrix.asan == false uses: ./.github/actions/test-linux - name: Test ${{ matrix.asan && 'OpCache' || 'Tracing JIT' }} + env: + GLIBC_TUNABLES: ${{ !matrix.asan && 'glibc.cpu.hwcaps=SHSTK' || '' }} uses: ./.github/actions/test-linux with: jitType: ${{ matrix.asan && 'disable' || 'tracing' }}