aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libgcc/config/i386/shadow-stack-unwind.h51
-rw-r--r--libgcc/unwind-generic.h2
-rw-r--r--libgcc/unwind.inc4
3 files changed, 50 insertions, 7 deletions
diff --git a/libgcc/config/i386/shadow-stack-unwind.h b/libgcc/config/i386/shadow-stack-unwind.h
index 2b02682..89d4416 100644
--- a/libgcc/config/i386/shadow-stack-unwind.h
+++ b/libgcc/config/i386/shadow-stack-unwind.h
@@ -54,10 +54,39 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
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__
+ shadow stack.
+
+ When popping a stack frame, we compare the return address on normal
+ stack against the return address on shadow stack. If they don't match,
+ return _URC_FATAL_PHASE2_ERROR for the corrupted return address on
+ normal stack. Don't check the return address for
+ 1. Non-catchable exception where exception_class == 0. Process will
+ be terminated.
+ 2. Zero return address which marks the outermost stack frame.
+ 3. Signal stack frame since kernel puts a restore token on shadow
+ stack.
+ */
#undef _Unwind_Frames_Increment
-#define _Unwind_Frames_Increment(context, frames) \
+#ifdef __x86_64__
+#define _Unwind_Frames_Increment(exc, context, frames) \
+ { \
+ frames++; \
+ if (exc->exception_class != 0 \
+ && _Unwind_GetIP (context) != 0 \
+ && !_Unwind_IsSignalFrame (context)) \
+ { \
+ _Unwind_Word ssp = _get_ssp (); \
+ if (ssp != 0) \
+ { \
+ ssp += 8 * frames; \
+ _Unwind_Word ra = *(_Unwind_Word *) ssp; \
+ if (ra != _Unwind_GetIP (context)) \
+ return _URC_FATAL_PHASE2_ERROR; \
+ } \
+ } \
+ }
+#else
+#define _Unwind_Frames_Increment(exc, context, frames) \
if (_Unwind_IsSignalFrame (context)) \
do \
{ \
@@ -83,5 +112,19 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
} \
while (0); \
else \
- frames++;
+ { \
+ frames++; \
+ if (exc->exception_class != 0 \
+ && _Unwind_GetIP (context) != 0) \
+ { \
+ _Unwind_Word ssp = _get_ssp (); \
+ if (ssp != 0) \
+ { \
+ ssp += 4 * frames; \
+ _Unwind_Word ra = *(_Unwind_Word *) ssp; \
+ if (ra != _Unwind_GetIP (context)) \
+ return _URC_FATAL_PHASE2_ERROR; \
+ } \
+ } \
+ }
#endif
diff --git a/libgcc/unwind-generic.h b/libgcc/unwind-generic.h
index a87c9b3..bf72128 100644
--- a/libgcc/unwind-generic.h
+++ b/libgcc/unwind-generic.h
@@ -292,6 +292,6 @@ EXCEPTION_DISPOSITION _GCC_specific_handler (PEXCEPTION_RECORD, void *,
#define _Unwind_Frames_Extra(frames)
/* Increment frame count. */
-#define _Unwind_Frames_Increment(context, frames) frames++
+#define _Unwind_Frames_Increment(exc, context, frames) frames++
#endif /* unwind.h */
diff --git a/libgcc/unwind.inc b/libgcc/unwind.inc
index 5efd8af..a7111a7 100644
--- a/libgcc/unwind.inc
+++ b/libgcc/unwind.inc
@@ -73,7 +73,7 @@ _Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc,
gcc_assert (!match_handler);
uw_update_context (context, &fs);
- _Unwind_Frames_Increment (context, frames);
+ _Unwind_Frames_Increment (exc, context, frames);
}
*frames_p = frames;
@@ -191,7 +191,7 @@ _Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc,
/* Update cur_context to describe the same frame as fs, and discard
the previous context if necessary. */
uw_advance_context (context, &fs);
- _Unwind_Frames_Increment (context, frames);
+ _Unwind_Frames_Increment (exc, context, frames);
}
*frames_p = frames;