From patchwork Sun Jun 28 07:02:35 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jesse Huang X-Patchwork-Id: 137965 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6B6904BA23C9 for ; Sun, 28 Jun 2026 07:05:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6B6904BA23C9 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=sifive.com header.i=@sifive.com header.a=rsa-sha256 header.s=google header.b=dSmMaB3z X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-dl1-x122c.google.com (mail-dl1-x122c.google.com [IPv6:2607:f8b0:4864:20::122c]) by sourceware.org (Postfix) with ESMTPS id 745C14BA23D2 for ; Sun, 28 Jun 2026 07:03:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 745C14BA23D2 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=sifive.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=sifive.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 745C14BA23D2 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::122c ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782630182; cv=none; b=BHj77bhc4if5uHnt7KG8PboME9iFB6Mkjyc0O3UWfsc9GIaLxLOgfXwwDVWFyCEAMplJMqZhEdFVnv5YwhXI3BIRPxh5upT24DgZsNFoHvQG1M1EOmTDEUH3ygpdUEMO6NAHHUqBc9ae4v4fckZlBmju5F2mdeu3O/YlouRaAsk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782630182; c=relaxed/simple; bh=P+s6AbTxwWXY1ixPDOvona1AFt+B7rHjSGH7F6f+cak=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=qM7dFdDbPHhIezZs0f0nHYmkXXSu91EvQw5XOKmN1K5ZiXjRHa+b/lbEghhu2rMhunmqjmYcpCvz7e+qN5UuPI5m+cMXgISJeNF7g4ENWOQ8m5GKL7CiLbc1t68x7XKgUEYC4bZWpYpg3iS9DPvDRl7ABmmX63mYcFOe/pSsLic= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=sifive.com header.i=@sifive.com header.a=rsa-sha256 header.s=google header.b=dSmMaB3z DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 745C14BA23D2 Received: by mail-dl1-x122c.google.com with SMTP id a92af1059eb24-13810b63a1aso5403361c88.1 for ; Sun, 28 Jun 2026 00:03:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; t=1782630181; x=1783234981; darn=sourceware.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yxP/b++u3YipNlwEtsSFfmFRwBmhNlSE4BreTYZR2cs=; b=dSmMaB3zPGxUHqZaBPVp/2YXC9nS0eA67uAyfxA9x1YwajQiyaSHl3JJPls9Unm8Zg MxnRYUupqsHpeArhoKxYjGeVR0NrN8QHdz4CUq82zwOBfxUhINSMZIEEHrD+ZMyDrpcZ MIAPggawS4O+50fwovSLZQ1xOTd6xa2UX/6n+iGrDWipOHQpkNQr5xb3ELzjcp2oM/F/ yQfpSN1A+BBDwE705Jh4eEV/OdxU8woOeaZxcD20fCY16O57+JwKwoFTN9FUpAiSX6EQ X6KReT4O6D9zaMq5B9p7+k2ugl5ljJvi/LjteTmHZSbd4sF88ch5iYE0rkDsAjKgs2Ab C8sw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782630181; x=1783234981; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=yxP/b++u3YipNlwEtsSFfmFRwBmhNlSE4BreTYZR2cs=; b=QXgwT02xhgwyjH+/mlS29vFlwPwKyuKjotuU1InqSW1BL0QIWplaoneVlquk8S08gw k3Gx07ZlbJoIa97ik1OBUkIViTK61Tlb3zWZTzjtQzZnzwbILfETYZEMUek2L8/AeVUn T6I9o2lVqtFC5xeSTOhyVcayxRF5idpEX/cuLZvE6ihg+VyJrObPsgQQCTO6vGVtL1mS Wt2tmPsvV5HbewAkFxn0E2e1u7iaqPoeO1FppFFKl9eXoc7jkpSnswchpu7I87FeJS3i fG0KXXjSpRGrBZFjz70ZHZ7I63l36CX+6dbXimXIb4Ct8uhYJ3WMRz8OX4R3uBtHXlGc JW3A== X-Gm-Message-State: AOJu0Yz9xAbtOBDOxoHJNCaG3zRyeU4mkQy3lFbMfsRx5P/XmnXo9rPF gMNfy63pg/lsCX2EeDXpE1e3y8EZUwTGoV/0Kq1/sTOlX8B77KECU/ysLgSnYEDiWk4Ecmg1cLf 5gcgLQvKverjUBobtck9GOz55GeoO6BdKT4eSgGGQ+Oz0scXvZ3XZE2hA7ARKeAecB1k3jQSyCt eF3ZAemBHGirZK/s9gYdfIgiuhY5tBuUbFs1mly3M7mu6eLSP/lrY= X-Gm-Gg: AfdE7cm12Uu+3OBesWK0HxZH0HMI3C2S9yeA37e1/pl0dP4TQfnzzSUwR4LskXHQjZF Y1cN858K0D6CVpfQHa05Az24KHvnx0YkHKWm6u/7DewzLT3Hrr12VE6tnmqAB1Y+b2Yry9RTjng hUb9QN8uT6s/kq5bM+Nr27bMDNZOcGjq4QoHJcTJtpsgMtoJNpFDszvUBK9dupEeEWGT0I4Q346 AOcwGs9eUJtJjt5/VmQvu/QsD9QZM5gE6sSIQL9T+Gl8SigCpn6bmI47OB95bdsiYKJfjh6cGCb UvJOlhtnPSB45VLabl3vUpH8MrXP9R+emhjaWFABPf//mX5AE/h/4R5iN6qjUmcXUb3LnG38izS 9Fi6bJ5PBjzAnKNovGFF7/diX5f0pzBIK+Fbmk1seWDYmw7JMbZbQfAqO9cNWavvyTc+SBD5dZI MybriG7fBeFIeq68StiIZtY8N0bsuzVIrhMUHFNsml X-Received: by 2002:a05:693c:3944:b0:30b:c502:23df with SMTP id 5a478bee46e88-30cab081836mr6054010eec.13.1782630181169; Sun, 28 Jun 2026 00:03:01 -0700 (PDT) Received: from sw08.internal.sifive.com ([4.53.31.132]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-30c7c8afc91sm35435166eec.14.2026.06.28.00.02.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 28 Jun 2026 00:03:00 -0700 (PDT) From: Jesse Huang To: libc-alpha@sourceware.org Cc: andrew@sifive.com, darius@bluespec.com, debug@rivosinc.com, jeffreyalaw@gmail.com, kito.cheng@sifive.com, palmer@dabbelt.com, schwab@suse.de, Jesse Huang Subject: [PATCH v5 10/16] riscv/cfi: Adjust setjmp/longjmp for shadow stack to work Date: Sun, 28 Jun 2026 00:02:35 -0700 Message-Id: <20260628070241.88310-11-jesse.huang@sifive.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260628070241.88310-1-jesse.huang@sifive.com> References: <20260628070241.88310-1-jesse.huang@sifive.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Since longjmp to a previous setjmp state can change the stack frame and involves stack frame unwinding, the shadow stack is also required to be unwound. The unwinding is implemented according to the Zicfiss specification by increasing the SSP by at most one page size (4K), to avoid accidentally pointing to another legal shadow stack page after the adjustment. The shadow stack pointer is stored in a wrapped sigset_t. By defining it inside a union, we can avoid changing the size of sigset_t and therefore jmp_buf. --- sysdeps/riscv/Makefile | 4 + sysdeps/riscv/__longjmp.S | 54 +++++++++++++ sysdeps/riscv/setjmp.S | 22 ++++++ sysdeps/unix/sysv/linux/riscv/jmp_buf-ssp.sym | 7 ++ sysdeps/unix/sysv/linux/riscv/setjmpP.h | 78 +++++++++++++++++++ 5 files changed, 165 insertions(+) create mode 100644 sysdeps/unix/sysv/linux/riscv/jmp_buf-ssp.sym create mode 100644 sysdeps/unix/sysv/linux/riscv/setjmpP.h diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile index b1f074a3eb..94e224615c 100644 --- a/sysdeps/riscv/Makefile +++ b/sysdeps/riscv/Makefile @@ -11,6 +11,10 @@ endif # of some assembler macros. ASFLAGS-.os += $(pic-ccflag) +ifeq ($(subdir),setjmp) +gen-as-const-headers += jmp_buf-ssp.sym +endif + ifeq (no,$(riscv-r-align)) ASFLAGS-.os += -Wa,-mno-relax ASFLAGS-.o += -Wa,-mno-relax diff --git a/sysdeps/riscv/__longjmp.S b/sysdeps/riscv/__longjmp.S index bea854199c..8ee0662b81 100644 --- a/sysdeps/riscv/__longjmp.S +++ b/sysdeps/riscv/__longjmp.S @@ -18,9 +18,12 @@ #include #include +#include +#include ENTRY (__longjmp) REG_L ra, 0*SZREG(a0) + REG_L t1, 0*SZREG(a0) REG_L s0, 1*SZREG(a0) REG_L s1, 2*SZREG(a0) REG_L s2, 3*SZREG(a0) @@ -50,8 +53,59 @@ ENTRY (__longjmp) FREG_L fs11,14*SZREG+11*SZFREG(a0) #endif +#ifdef __riscv_shadow_stack + /* skip unwinding if ss is not enabled */ + ssrdp ra + beqz ra, .Lfin + REG_L t0, SSP_OFFSET(a0) + REG_L a0, SSP_BASE_OFFSET(a0) + REG_L t2, TLS_SSP_BASE_OFFSET(tp) + bne a0, t2, .Ldifferent_stack +.Lunwind: + bleu t0, ra, .Lfin + /* Increase ssp by at most one page size to ensure the adjustment + always runs into a guard page before accidentally pointing to + another legal shadow stack page */ + /* ra = (t0 - ra >= 4096) ? ra + 4096 : t0 */ + lui a0, 1 + add ra, ra, a0 + bleu ra, t0, 1f + mv ra, t0 +1: + csrw ssp, ra + /* Test if the location pointed by ssp is legal */ + sspush x5 + sspopchk x5 + j .Lunwind +.Ldifferent_stack: + /* Create restore token */ + sspush ra + mv a4, t0 + +.Lfind_rstor_token: + /* Probe and validate target restore token */ + ssamoswap.d a3, x0, (a4) + addi a2, a4, 8 + beq a3, a2, .Lswitch_stack + /* Restore the shadow stack and try the next slot */ + ssamoswap.d x0, a3, (a4) + addi a4, a4, -8 + j .Lfind_rstor_token + +.Lswitch_stack: + /* Switch stack: update ssp and base */ + csrw ssp, t0 + REG_S a0, TLS_SSP_BASE_OFFSET(tp) +.Lfin: +#endif seqz a0, a1 add a0, a0, a1 # a0 = (a1 == 0) ? 1 : a1 +#ifdef __riscv_landing_pad + /* Use indirect branch if CFI is enabled */ + jr t1 +#else + mv ra, t1 ret +#endif END (__longjmp) diff --git a/sysdeps/riscv/setjmp.S b/sysdeps/riscv/setjmp.S index af1910b86d..0406b23956 100644 --- a/sysdeps/riscv/setjmp.S +++ b/sysdeps/riscv/setjmp.S @@ -18,6 +18,8 @@ #include #include +#include +#include ENTRY (_setjmp) li a1, 0 @@ -58,6 +60,26 @@ ENTRY (__sigsetjmp) FREG_S fs11,14*SZREG+11*SZFREG(a0) #endif +#ifdef __riscv_shadow_stack + /* Skip if shadow stack is not enabled */ + ssrdp t0 + beqz t0, .Lfin + + /* Read ssp_base from TLS */ + REG_L t2, TLS_SSP_BASE_OFFSET(tp) + bnez t2, .Lbase_saved + + /* if not found, use current ssp as the marker */ + mv t2, t0 + REG_S t2, TLS_SSP_BASE_OFFSET(tp) + +.Lbase_saved: + /* Save caller's ssp and base marker to jmp_buf */ + REG_S t0, SSP_OFFSET(a0) + REG_S t2, SSP_BASE_OFFSET(a0) +.Lfin: +#endif + #if !IS_IN (libc) && IS_IN (rtld) /* In ld.so we never save the signal mask. */ li a0, 0 diff --git a/sysdeps/unix/sysv/linux/riscv/jmp_buf-ssp.sym b/sysdeps/unix/sysv/linux/riscv/jmp_buf-ssp.sym new file mode 100644 index 0000000000..bf944969f7 --- /dev/null +++ b/sysdeps/unix/sysv/linux/riscv/jmp_buf-ssp.sym @@ -0,0 +1,7 @@ +#include +#include +#undef __saved_mask + +-- +SSP_OFFSET offsetof(struct __jmp_buf_tag, __saved_mask.__saved.__ssp) +SSP_BASE_OFFSET offsetof(struct __jmp_buf_tag, __saved_mask.__saved.__ssp_base) diff --git a/sysdeps/unix/sysv/linux/riscv/setjmpP.h b/sysdeps/unix/sysv/linux/riscv/setjmpP.h new file mode 100644 index 0000000000..43cb28e2d1 --- /dev/null +++ b/sysdeps/unix/sysv/linux/riscv/setjmpP.h @@ -0,0 +1,78 @@ +/* Internal header file for . Linux/risc-v version. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _SETJMPP_H +#define _SETJMPP_H 1 + +#include +#include +#include + +/* Number of bits per long. */ +#define _JUMP_BUF_SIGSET_BITS_PER_WORD (8 * sizeof (unsigned long int)) +/* This holds the number of signals, 512 should be sufficient for future. + expansion */ +#define _JUMP_BUF_SIGSET_NSIG 512 +/* Number of longs to hold all signals. */ +#define _JUMP_BUF_SIGSET_NWORDS \ + (ALIGN_UP (_JUMP_BUF_SIGSET_NSIG, _JUMP_BUF_SIGSET_BITS_PER_WORD) \ + / _JUMP_BUF_SIGSET_BITS_PER_WORD) + +typedef struct + { + unsigned long int __val[_JUMP_BUF_SIGSET_NWORDS]; + } __jmp_buf_sigset_t; + +typedef union + { + __sigset_t __saved_mask_compat; + struct + { + __jmp_buf_sigset_t __saved_mask; + /* Used for shadow stack pointer. NB: Shadow stack pointer + must have the same alignment as __saved_mask. Otherwise + offset of __saved_mask will be changed. */ + unsigned long int __ssp; + unsigned long int __ssp_base; + } __saved; + } __jmpbuf_arch_t; + +/* has + + NB: We use setjmp in thread cancellation and this saves the shadow + stack register, but __libc_unwind_longjmp doesn't restore the shadow + stack register since cancellation never returns after longjmp. */ +#undef __sigset_t +#define __sigset_t __jmpbuf_arch_t +#include +#undef __saved_mask +#define __saved_mask __saved_mask.__saved.__saved_mask + +#include + +typedef struct + { + unsigned long int __val[__NSIG_WORDS]; + } __sigprocmask_sigset_t; + +extern jmp_buf ___buf; +extern __typeof (___buf[0].__saved_mask) ___saved_mask; +_Static_assert (sizeof (___saved_mask) >= sizeof (__sigprocmask_sigset_t), + "size of ___saved_mask < size of __sigprocmask_sigset_t"); + +#endif /* setjmpP.h */