> Am 16.12.2023 um 16:56 schrieb H.J. Lu <hjl.to...@gmail.com>:
>
> Linux CET kernel places a restore token on shadow stack followed by
> optional additional information for signal handler to enhance security.
> The restore token is the previous shadow stack pointer with bit 63 set.
> It is usually transparent to user programs since kernel will pop the
> restore token and additional information when signal handler returns.
> But when an exception is thrown from a signal handler, now we need to
> pop the restore token and additional information from shadow stack.
> For x86-64, we just need to get the previous shadow stack pointer from
> the restore token. For i386, shadow stack is unsupported.
>
> To be compatible with the old unwinder which doesn't use the restore
> token to skip shadow stack frames used by signal handler, Linux kernel
> won't put additional information after the restore token by default.
> Define __cet_features to 1 to indicate that unwinder uses the restore
> token to skip shadow stack frames used by signal handler. It can be
> checked by glibc before enabling additional information in shadow stack
> for signal handler.
Doesn’t the check need to be two ways
To support kernels not doing this? Or
Not do it if the high bit isn’t set?
Richard
> * config/i386/libgcc-glibc.ver: Add __cet_features to
> GCC_CET_FEATURES.
> * config/i386/shadow-stack-unwind.h (_Unwind_Frames_Increment):
> Only define for x86-64. Get the previous shadow stack pointer
> from the restore token and skip to the previous frame.
> (__cet_features): New.
> ---
> libgcc/config/i386/libgcc-glibc.ver | 4 ++
> libgcc/config/i386/shadow-stack-unwind.h | 84 +++++++-----------------
> 2 files changed, 29 insertions(+), 59 deletions(-)
>
> diff --git a/libgcc/config/i386/libgcc-glibc.ver
> b/libgcc/config/i386/libgcc-glibc.ver
> index 1c4665719da..9a8525757a4 100644
> --- a/libgcc/config/i386/libgcc-glibc.ver
> +++ b/libgcc/config/i386/libgcc-glibc.ver
> @@ -152,6 +152,10 @@ GCC_4.8.0 {
> __cpu_model
> __cpu_indicator_init
> }
> +
> +GCC_CET_FEATURES {
> + __cet_features
> +}
> %else
> GCC_4.4.0 {
> __addtf3
> diff --git a/libgcc/config/i386/shadow-stack-unwind.h
> b/libgcc/config/i386/shadow-stack-unwind.h
> index e07ab4a10e4..afcce4b482d 100644
> --- a/libgcc/config/i386/shadow-stack-unwind.h
> +++ b/libgcc/config/i386/shadow-stack-unwind.h
> @@ -43,18 +43,15 @@ 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.
> +/* Linux CET kernel places a restore token on shadow stack followed by
> + additional information for signal handler to enhance security. The
> + restore token is the previous shadow stack pointer with bit 63 set.
> + It is usually transparent to user programs since kernel will pop the
> + restore token and additional information when signal handler returns.
> + But when an exception is thrown from a signal handler, now we need to
> + pop the restore token and additional information from shadow stack.
> + For x86-64, we just need to get the previous shadow stack pointer from
> + the restore token. For i386, shadow stack is unsupported.
>
> 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,
> @@ -66,65 +63,34 @@ see the files COPYING3 and COPYING.RUNTIME respectively.
> If not, see
> 3. Signal stack frame since kernel puts a restore token on shadow
> stack.
> */
> -#undef _Unwind_Frames_Increment
> #ifdef __x86_64__
> +#undef _Unwind_Frames_Increment
> #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) \
> { \
> - _Unwind_Word ssp = _get_ssp (); \
> - if (ssp != 0) \
> + ssp += 8 * frames; \
> + if (_Unwind_IsSignalFrame (context)) \
> { \
> - ssp += 8 * frames; \
> - _Unwind_Word ra = *(_Unwind_Word *) ssp; \
> - if (ra != _Unwind_GetIP (context)) \
> - return _URC_FATAL_PHASE2_ERROR; \
> + /* Get the previous SSP. */ \
> + _Unwind_Word prev_ssp \
> + = ((*(_Unwind_Word *) ssp) \
> + & ~0x8000000000000000LL); \
> + /* Skip to the previous frame. */ \
> + frames += (prev_ssp - ssp) / 8 - 1; \
> } \
> - } \
> - }
> -#else
> -#define _Unwind_Frames_Increment(exc, 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++; \
> - if (exc->exception_class != 0 \
> - && _Unwind_GetIP (context) != 0) \
> - { \
> - _Unwind_Word ssp = _get_ssp (); \
> - if (ssp != 0) \
> + else if (_Unwind_GetIP (context) != 0 \
> + && exc->exception_class != 0) \
> { \
> - ssp += 4 * frames; \
> _Unwind_Word ra = *(_Unwind_Word *) ssp; \
> if (ra != _Unwind_GetIP (context)) \
> return _URC_FATAL_PHASE2_ERROR; \
> } \
> } \
> }
> +
> +/* Bit 0: Unwinder uses the restore token in signal frame. */
> +const int __cet_features = 1;
> #endif
> --
> 2.43.0
>