From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1039) id A038E3858D32; Mon, 17 Oct 2022 21:22:32 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A038E3858D32 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1666041752; bh=ybnsQ/QkPbEkL1v9Ghha0TCZUaNGql5CGzvB4Ly5cqM=; h=From:To:Subject:Date:From; b=EWRnpWZ60zfxCffKMtIe3g/LKmc01yaf5rMl7Ol/Vwd0sCGOj0NKPueUsJlAY94Bt HfOZrlGok1SE/knAKeDwYc/JYu1+Kny5/MehFQZ79VTrk2KboIvdrGPJuP05MGaGjh BvkUuwaM2xnIsdBw3ry7oZ3gUFMbaLskRofG77Wc= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: H.J. Lu To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-3343] x86: Check corrupted return address when unwinding stack X-Act-Checkin: gcc X-Git-Author: H.J. Lu X-Git-Refname: refs/heads/master X-Git-Oldrev: 84807af0ca6dfdb81abb8e925ce32acbcab29868 X-Git-Newrev: 9072db9d5b549db5e2f14335ac0adc7735d43bc6 Message-Id: <20221017212232.A038E3858D32@sourceware.org> Date: Mon, 17 Oct 2022 21:22:32 +0000 (GMT) List-Id: https://gcc.gnu.org/g:9072db9d5b549db5e2f14335ac0adc7735d43bc6 commit r13-3343-g9072db9d5b549db5e2f14335ac0adc7735d43bc6 Author: H.J. Lu Date: Thu Aug 11 16:21:23 2022 -0700 x86: Check corrupted return address when unwinding stack If shadow stack is enabled, when unwinding stack, we count how many stack frames we pop to reach the landing pad and adjust shadow stack by the same amount. When counting the 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. * unwind-generic.h (_Unwind_Frames_Increment): Add the EXC argument. * unwind.inc (_Unwind_RaiseException_Phase2): Pass EXC to _Unwind_Frames_Increment. (_Unwind_ForcedUnwind_Phase2): Likewise. * config/i386/shadow-stack-unwind.h (_Unwind_Frames_Increment): Take the EXC argument. Return _URC_FATAL_PHASE2_ERROR if the return address on normal stack doesn't match the return address on shadow stack. Diff: --- libgcc/config/i386/shadow-stack-unwind.h | 51 +++++++++++++++++++++++++++++--- libgcc/unwind-generic.h | 2 +- libgcc/unwind.inc | 4 +-- 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 2b02682bdae..89d44165000 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 a87c9b3ccf6..bf721282d03 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 5efd8af1b15..a7111a7b3a8 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;