diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2020-02-10 07:58:45 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2020-02-10 07:59:10 -0800 |
commit | bf6465d0461234ccd45ae34d5e2375a0bee0081d (patch) | |
tree | 71a56036daba549bcf0290f3780a4b27a1304c37 /libgcc | |
parent | 1cad5e89a9e1b4ffa47bc6e3551643b342f6cfe8 (diff) | |
download | gcc-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.h | 43 |
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 |