When shadow stack is enabled, selftests/x86/sigreturn_64 triggers a fault when doing sigreturn to 32-bit context but the task's shadow stack pointer is above 32-bit address range. Fix it by: - Allocate a small shadow stack below 32-bit address, - Switch to the new shadow stack, - Run tests, - Switch back to the original 64-bit shadow stack. Signed-off-by: Yu-cheng Yu <yu-cheng.yu@xxxxxxxxx> --- tools/testing/selftests/x86/sigreturn.c | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c index 57c4f67f16ef..5bcd74d416ff 100644 --- a/tools/testing/selftests/x86/sigreturn.c +++ b/tools/testing/selftests/x86/sigreturn.c @@ -45,6 +45,14 @@ #include <stdbool.h> #include <sys/ptrace.h> #include <sys/user.h> +#include <x86intrin.h> +#include <asm/prctl.h> +#include <sys/prctl.h> + +#ifdef __x86_64__ +int arch_prctl(int code, unsigned long *addr); +#define ARCH_CET_ALLOC_SHSTK 0x3004 +#endif /* Pull in AR_xyz defines. */ typedef unsigned int u32; @@ -766,6 +774,20 @@ int main() int total_nerrs = 0; unsigned short my_cs, my_ss; +#ifdef __x86_64__ + /* Alloc a shadow stack within 32-bit address range */ + unsigned long arg, ssp_64, ssp_32; + ssp_64 = _get_ssp(); + + if (ssp_64 != 0) { + arg = 0x1001; + arch_prctl(ARCH_CET_ALLOC_SHSTK, &arg); + ssp_32 = arg + 0x1000 - 8; + asm volatile("RSTORSSP (%0)\n":: "r" (ssp_32)); + asm volatile("SAVEPREVSSP"); + } +#endif + asm volatile ("mov %%cs,%0" : "=r" (my_cs)); asm volatile ("mov %%ss,%0" : "=r" (my_ss)); setup_ldt(); @@ -870,6 +892,12 @@ int main() #ifdef __x86_64__ total_nerrs += test_nonstrict_ss(); + + if (ssp_64 != 0) { + ssp_64 -= 8; + asm volatile("RSTORSSP (%0)\n":: "r" (ssp_64)); + asm volatile("SAVEPREVSSP"); + } #endif return total_nerrs ? 1 : 0; -- 2.21.0