aboutsummaryrefslogtreecommitdiff
path: root/libgcc
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2020-02-10 07:58:45 -0800
committerH.J. Lu <hjl.tools@gmail.com>2020-02-10 07:59:10 -0800
commitbf6465d0461234ccd45ae34d5e2375a0bee0081d (patch)
tree71a56036daba549bcf0290f3780a4b27a1304c37 /libgcc
parent1cad5e89a9e1b4ffa47bc6e3551643b342f6cfe8 (diff)
downloadgcc-bf6465d0461234ccd45ae34d5e2375a0bee0081d.zip
gcc-bf6465d0461234ccd45ae34d5e2375a0bee0081d.tar.gz
gcc-bf6465d0461234ccd45ae34d5e2375a0bee0081d.tar.bz2
i386: Properly pop restore token in signal frame
Linux CET kernel places a restore token on shadow stack for signal handler to enhance security. The restore token is 8 byte and aligned to 8 bytes. It is usually transparent to user programs since kernel will pop the restore token when signal handler returns. But when an exception is thrown from a signal handler, now we need to pop the restore token from shadow stack. For x86-64, we just need to treat the signal frame as normal frame. For i386, we need to search for the restore token to check if the original shadow stack is 8 byte aligned. If the original shadow stack is 8 byte aligned, we just need to pop 2 slots, one restore token, from shadow stack. Otherwise, we need to pop 3 slots, one restore token + 4 byte padding, from shadow stack. This patch also includes 2 tests, one has a restore token with 4 byte padding and one without. Tested on Linux/x86-64 CET machine with and without -m32. libgcc/ PR libgcc/85334 * config/i386/shadow-stack-unwind.h (_Unwind_Frames_Increment): New. gcc/testsuite/ PR libgcc/85334 * g++.target/i386/pr85334-1.C: New test. * g++.target/i386/pr85334-2.C: Likewise.
Diffstat (limited to 'libgcc')
-rw-r--r--libgcc/config/i386/shadow-stack-unwind.h43
1 files changed, 43 insertions, 0 deletions
diff --git a/libgcc/config/i386/shadow-stack-unwind.h b/libgcc/config/i386/shadow-stack-unwind.h
index a0244d2e..201b2153 100644
--- a/libgcc/config/i386/shadow-stack-unwind.h
+++ b/libgcc/config/i386/shadow-stack-unwind.h
@@ -49,3 +49,46 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
} \
} \
while (0)
+
+/* Linux CET kernel places a restore token on shadow stack for signal
+ handler to enhance security. The restore token is 8 byte and aligned
+ to 8 bytes. It is usually transparent to user programs since kernel
+ will pop the restore token when signal handler returns. But when an
+ exception is thrown from a signal handler, now we need to pop the
+ restore token from shadow stack. For x86-64, we just need to treat
+ the signal frame as normal frame. For i386, we need to search for
+ the restore token to check if the original shadow stack is 8 byte
+ aligned. If the original shadow stack is 8 byte aligned, we just
+ need to pop 2 slots, one restore token, from shadow stack. Otherwise,
+ we need to pop 3 slots, one restore token + 4 byte padding, from
+ shadow stack. */
+#ifndef __x86_64__
+#undef _Unwind_Frames_Increment
+#define _Unwind_Frames_Increment(context, frames) \
+ if (_Unwind_IsSignalFrame (context)) \
+ do \
+ { \
+ _Unwind_Word ssp, prev_ssp, token; \
+ ssp = _get_ssp (); \
+ if (ssp != 0) \
+ { \
+ /* Align shadow stack pointer to the next \
+ 8 byte aligned boundary. */ \
+ ssp = (ssp + 4) & ~7; \
+ do \
+ { \
+ /* Look for a restore token. */ \
+ token = (*(_Unwind_Word *) (ssp - 8)); \
+ prev_ssp = token & ~7; \
+ if (prev_ssp == ssp) \
+ break; \
+ ssp += 8; \
+ } \
+ while (1); \
+ frames += (token & 0x4) ? 3 : 2; \
+ } \
+ } \
+ while (0); \
+ else \
+ frames++;
+#endif