From patchwork Sat Dec 16 15:56:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 82297 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7E232385841E for ; Sat, 16 Dec 2023 15:56:31 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pg1-x530.google.com (mail-pg1-x530.google.com [IPv6:2607:f8b0:4864:20::530]) by sourceware.org (Postfix) with ESMTPS id 7C5233858D33 for ; Sat, 16 Dec 2023 15:56:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7C5233858D33 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 7C5233858D33 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::530 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1702742176; cv=none; b=G9SgnHYrdERKnoScfQn4HDZAn6+wERfdeilmCB8uYmYkvkFqPFf2rIXEBKXE8o50Yy8nBfU7QkOq8lT9qvYd3lagOpbnfjuCn3Lxj5ONjmrlxMt76dpSD1KWPW+PXj99RyynXdldeFU2WUdxWRejJh1uh6eQNo5fYBj1Vagu+KY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1702742176; c=relaxed/simple; bh=O0w+phGMXDDEBo0tKF5UCs3ozrVIjmItIisuBSfwFKU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=A2a4v+4Rm/JCXg8PBML/WwFh6OfH5/ntCzUaD0HYKDdJkyX03arXYrSmGQZ7NzAyQ6xUPerr8vVf3O1pz6xhFHiegumYRamq3DuIXLJFve9+VnBpXXNfnxCT+iv+a/xfQsPi/xNCGr5eb+NocKEKLsyZHKaiwpv/c/COoMHDRCI= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pg1-x530.google.com with SMTP id 41be03b00d2f7-5c690c3d113so1362391a12.1 for ; Sat, 16 Dec 2023 07:56:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1702742173; x=1703346973; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=BvDzdnW186TZKFd+BK5dkJ5NVUyJlT2oL4v9NS5XX9I=; b=mUD0M0ycGe6gCPFoo4y52jd/6oBmrkdDlblw5zVW0MH4sgMtm45JwdXyWDXDP79C5r 6ySPv+8cePAljOaVWrJjGfFyNz+JMa01bbBamDpRmirNZgKAht4Jdv5jlBh72JbFkmKj 7apXsZXZpisy7qnW9Dj5k3T3WQ83bMnxuhNNZ+yboGn2tXjRMBHFYd7SjWHWkB8UguuL b8nmB/BLw6xvndMK0VDZvFowKxgEDBOFZmNxfWjbrWsB6p2MLBfA8/JFCnLv8668hpjX Pxsgxqy7YAYTgHYxLQIGWMwQl2SPaetLXX9t41Sh5lnqRNsGyMm6twAV1EpcIE+A5dnY h+NA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702742173; x=1703346973; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=BvDzdnW186TZKFd+BK5dkJ5NVUyJlT2oL4v9NS5XX9I=; b=pnWsTWXZmZJg6x7ptVh0IQ5YzmMqRu+KlGzXDBI8xOjuTz9paytRiqQQiFD+7M3b4o PDq4gWfKnfOPsHr/GDYuy8VZ4DqiWDjxlxsRlyh9E3p7X/6p3oaxGBZ88068xf+Mko0g EZZ9SN3hDPI4zVAyG0Wo/HgyhHVwfey9BMzk5uKkUwsSRKXwauQrt0/prFlWm1r5zoEh gar0dV8cOpJNprEJwcgSvHWT30P5Y0DEOISS+C5qJq+psn/H+3KXjsofz+f3Q2FhBWZm 4M8Jl4UHPc9K2MC142Gu4Am0Qm+tATY2mfffSx82yOXXsrryn1A+PTIShDGQhvRwMJ2o O0Wg== X-Gm-Message-State: AOJu0YypDr61rusbesSfzJ5Q8Av86p2J5/pMNxielmLp64mmk5xuDyvb kfBxkB3OHgRr7rAi8uPFCJBYAVd2uDs= X-Google-Smtp-Source: AGHT+IGUdnjQ4rYlWFogHxOpHjckoCpTiMiriK+LsdIdxjdHs66KE63II5PqlO/uRBD2D3hpy/y7qg== X-Received: by 2002:a17:902:7d8a:b0:1d2:eb05:9d05 with SMTP id a10-20020a1709027d8a00b001d2eb059d05mr12140346plm.90.1702742172853; Sat, 16 Dec 2023 07:56:12 -0800 (PST) Received: from gnu-cfl-3.localdomain ([172.59.129.147]) by smtp.gmail.com with ESMTPSA id f11-20020a170902ce8b00b001cc307bcdbdsm16109172plg.211.2023.12.16.07.56.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 16 Dec 2023 07:56:11 -0800 (PST) Received: from gnu-cfl-3.. (localhost [IPv6:::1]) by gnu-cfl-3.localdomain (Postfix) with ESMTP id 583AD740387; Sat, 16 Dec 2023 07:56:09 -0800 (PST) From: "H.J. Lu" To: gcc-patches@gcc.gnu.org Cc: rick.p.edgecombe@intel.com Subject: [PATCH] x86: Get the previous shadow stack pointer from the restore token Date: Sat, 16 Dec 2023 07:56:09 -0800 Message-ID: <20231216155609.562884-1-hjl.tools@gmail.com> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 X-Spam-Status: No, score=-3024.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org 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. * 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