From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1944) id 818FB385841D; Wed, 10 Apr 2024 10:48:59 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 818FB385841D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1712746139; bh=TPA2DSNGkVLQ2bmLz0L9F9PP/egEiRyeh3e3okF7TXs=; h=From:To:Subject:Date:From; b=WEjYXaQVluClKDYU13znATTnDWVbiFwT7RIjhGWWMXCrEIyWaBrPQVUK3sRzqmff3 /x1mto9O2Yfomd+vH2Rw2QrjxtOot0DuyXXxEE4tvYJP4iFjfw3etXA96wuxyXX02c MkeJ4mGNVSpolSuXB2781ogIiWV7j70Rqmg6wjFY= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Szabolcs Nagy To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/ARM/heads/gcs)] aarch64: Add GCS support to the unwinder X-Act-Checkin: gcc X-Git-Author: Szabolcs Nagy X-Git-Refname: refs/vendors/ARM/heads/gcs X-Git-Oldrev: 2a9d500c8f2fd1004cdcbcdec063681dbb0bb1f1 X-Git-Newrev: 2185dc7cdb6d536e4d9a49a77c552e58041cb0bc Message-Id: <20240410104859.818FB385841D@sourceware.org> Date: Wed, 10 Apr 2024 10:48:59 +0000 (GMT) List-Id: https://gcc.gnu.org/g:2185dc7cdb6d536e4d9a49a77c552e58041cb0bc commit 2185dc7cdb6d536e4d9a49a77c552e58041cb0bc Author: Szabolcs Nagy Date: Wed Apr 19 14:01:36 2023 +0100 aarch64: Add GCS support to the unwinder TODO: - Follows the current linux ABI that uses single signal entry token and shared shadow stack between thread and alt stack. - Could be behind __ARM_FEATURE_GCS_DEFAULT ifdef (only do anything special with gcs compat codegen) but there is a runtime check anyway. libgcc/ChangeLog: * config/aarch64/aarch64-unwind.h (_Unwind_Frames_Extra): Update. (_Unwind_Frames_Increment): Define. Diff: --- libgcc/config/aarch64/aarch64-unwind.h | 59 +++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h index daf96624b5e..c22a3fc20d2 100644 --- a/libgcc/config/aarch64/aarch64-unwind.h +++ b/libgcc/config/aarch64/aarch64-unwind.h @@ -78,6 +78,9 @@ aarch64_demangle_return_addr (struct _Unwind_Context *context, return addr; } +/* GCS enable flag for chkfeat instruction. */ +#define CHKFEAT_GCS 1 + /* SME runtime function local to libgcc, streaming compatible and preserves more registers than the base PCS requires, but we don't rely on that here. */ @@ -85,12 +88,66 @@ __attribute__ ((visibility ("hidden"))) void __libgcc_arm_za_disable (void); /* Disable the SME ZA state in case an unwound frame used the ZA - lazy saving scheme. */ + lazy saving scheme. And unwind the GCS for EH. */ #undef _Unwind_Frames_Extra #define _Unwind_Frames_Extra(x) \ do \ { \ __libgcc_arm_za_disable (); \ + if (__builtin_aarch64_chkfeat (CHKFEAT_GCS) == 0) \ + { \ + for (_Unwind_Word n = (x); n != 0; n--) \ + __builtin_aarch64_gcspopm (); \ + } \ + } \ + while (0) + +/* On signal entry the OS places a token on the GCS that can be used to + verify the integrity of the GCS pointer on signal return. It also + places the signal handler return address (the restorer that calls the + signal return syscall) on the GCS so the handler can return. + Because of this token, each stack frame visited during unwinding has + exactly one corresponding entry on the GCS, so the frame count is + the number of entries that will have to be popped at EH return time. + + Note: This depends on the GCS signal ABI of the OS. + + When unwinding across a stack frame for each frame the corresponding + entry is checked on the GCS against the computed return address from + the normal stack. If they don't match then _URC_FATAL_PHASE2_ERROR + is returned. This check is omitted if + + 1. GCS is disabled. Note: asynchronous GCS disable is supported here + if GCSPR and the GCS remains readable. + 2. Non-catchable exception where exception_class == 0. Note: the + pthread cancellation implementation in glibc sets exception_class + to 0 when the unwinder is used for cancellation cleanup handling, + so this allows the GCS to get out of sync during cancellation. + This weakens security but avoids an ABI break in glibc. + 3. Zero return address which marks the outermost stack frame. + 4. Signal stack frame, the GCS entry is an OS specific token then + with the top bit set. + */ +#undef _Unwind_Frames_Increment +#define _Unwind_Frames_Increment(exc, context, frames) \ + do \ + { \ + frames++; \ + if (__builtin_aarch64_chkfeat (CHKFEAT_GCS) != 0 \ + || exc->exception_class == 0 \ + || _Unwind_GetIP (context) == 0) \ + break; \ + const _Unwind_Word *gcs = __builtin_aarch64_gcspr (); \ + if (_Unwind_IsSignalFrame (context)) \ + { \ + if (gcs[frames] >> 63 == 0) \ + return _URC_FATAL_PHASE2_ERROR; \ + } \ + else \ + { \ + if (gcs[frames] != _Unwind_GetIP (context)) \ + return _URC_FATAL_PHASE2_ERROR; \ + } \ } \ while (0)