From patchwork Sun Jun 28 07:02:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jesse Huang X-Patchwork-Id: 137973 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 2F7C84BA2E35 for ; Sun, 28 Jun 2026 07:10:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2F7C84BA2E35 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=DdVzfwQq X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-dy1-x132d.google.com (mail-dy1-x132d.google.com [IPv6:2607:f8b0:4864:20::132d]) by sourceware.org (Postfix) with ESMTPS id D015A4BA23CA for ; Sun, 28 Jun 2026 07:03:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D015A4BA23CA 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 D015A4BA23CA Authentication-Results: sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::132d ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782630190; cv=none; b=CLqUFhXrnXkKFnhJ19jzJ/gMgjCha7gHnLiilY3NFy2YaTgvTicDdgufUSO+2eOzf/0V6Ec14lSF74FW9BgrAeuqY3ATSRevaMb3tppfc+Y01BKHy3JlIGTZnObgO1/72+k+m8pP6/DJUkz4LDKoR5LsaabSlKOHyEK8VJFOLtY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782630190; c=relaxed/simple; bh=jntNJVsvhVz/2mfxCbIFjpqc3kaHCp3QnNrrTGZcpOk=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=Wsb9QqClaNzwkCoJHOcOQEnIXLzmo9sPaz+N1dXPqQwl1Unty3K0jS3L0M6RBXYTJ+8Wb5QAnfuuDKQTnY+iqV0cpS9PQ3iZPMqyq6EbsQB/cDWyA9hjArynW5zrchmPrgFe7P12erc/PT14N7bjfLLbGJ/Clp966/xBL0tkWl8= 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=DdVzfwQq DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D015A4BA23CA Received: by mail-dy1-x132d.google.com with SMTP id 5a478bee46e88-30c591fb1cbso3585707eec.1 for ; Sun, 28 Jun 2026 00:03:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; t=1782630189; x=1783234989; 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=liNFo1+3j4zFNejGWoKxXosjrFNl01MFBLsvwG+NcjA=; b=DdVzfwQqoWsOJdIu9TLhi0jHEu5HJX8jtgFToccdMbRiBQC3+FUiji3bgpz2BLy4yi t8hE/VN2pD+45UrVQuSiK+SiVBlfLGKzRu2cuMqU+fdOn7EHyBvr7lXc+jCoeUXE4oka 3iXdZPew36ONfu9A2Cp0h1/4ZFHlEVkKOPmOfjc0A7l2cDLZj1G/QdFdWQZwFC91Awpy SO0ym2kLZII7fhTbt3c5bwqb7X7RaKSBwmYF6naJBGcsXHoZJMmZSnf//FktqQkQ8kBo 1GLgZaePKFUs30ddXxayeqLVpH56ZnsHpEU6G3Uj38Uhg+Y/ziGGBQBvurLDfFe9h8ky tCFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782630189; x=1783234989; 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=liNFo1+3j4zFNejGWoKxXosjrFNl01MFBLsvwG+NcjA=; b=PzblZ8cHwLAHCpJYZIfjCLPRC7gCpoDhFE5hNAumRbgHl71+h86v4auv+AI+wEc3v/ Io1GnKNP6x7q1HD/hsmPqr8Cn7jU97MLRAlxPFjFd6BR+GlICoiFK8Z0u24Rszv6A6f5 Cz3Ug/jQnoEAeBRGEJyEKh3AOTqlsK7RZO87WmAPUQDcuovNev5nWNZYW49wQQ9vZvf8 JRdyCJpOFlZqkiKVwxhldu866dy6z7guqMZZ5fF3xKYnnBjd+FxpqOUOXGNySpktSL5U AL2Aq+SIFwsnKoydclinL4CVzunTqCd0xr3/+66r8FpTrqS0BeCbOIruUCCEF74Ao7bD GROg== X-Gm-Message-State: AOJu0Yw9ZjLFdm2yShlyDoKXlC8zyqA6RFevhcx3NmW2SwzbcHjtTtlX LavKd1CE5h7FA6v0Q+aNDE/cph+E5s5ZIcdbQ/C61KhDpRHYKlzNgn93tlPHqsaoxxARpo0WrsV /oZvjI9gt5NWEWmXZglB49nL1/NPrW/V9LJDLGrTt10btKWbaSmFNM9xEf4mdg1iLdnP3T7eNWD SFmkBRaYrjAfl4R7yCP2dgKirdY5sS0JNn3ujdLrxHdKnDcFmgiW0= X-Gm-Gg: AfdE7cn9eIpKJ/f8uYHbKC9AwZeMogXJYZOJL24eyCnuc6z5AZ0QdUhRsVhPwmttuCb XLyihd4MMJ9ilkWbMJt7xKZ37AlChP5Um83hxiM1XC2CjlcXwpicu9BAaf+Xoqkeqtc824GZU3Y Vh8a1LAFSKDeVDauxJPmiE2zNxS6xR5aGui91Tk3+zIDyf/rgCnjoPaLzgoA5LfzXkePd9PsMw2 6mrbSEvTmmwocX0LkZdSgzceZYYYFyTPEF5j+BXOAfVpowX17sANrjgdP5Rh8mZHtsLvK7mJX3M lE99WyZ8xfdpsZ4EZJ0iEtkZSZCQNydaEWYS6QTKU0HhGuhTQ2lt+NBdRYM6u7GB9qkEncTqvaa +gxu/4Fk/mcMredqmdd8+wy61GKJZ7VMqbNxQLboOWORvP8609mATYafgRGyJauZJVxnEVIzY27 Pq+L6XqTkHksd1ojkKd6Q+Fe3DmvLEuNZMP1K6uHA/ X-Received: by 2002:a05:7300:4312:b0:306:f474:738c with SMTP id 5a478bee46e88-30c84b8d68dmr12429206eec.13.1782630188511; Sun, 28 Jun 2026 00:03:08 -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.03.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 28 Jun 2026 00:03:07 -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 , Nia Su Subject: [PATCH v5 15/16] riscv/cfi: Support ucontext under CFI Date: Sun, 28 Jun 2026 00:02:40 -0700 Message-Id: <20260628070241.88310-16-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 This patch adds shadow stack and landing pad support to the ucontext library. Shadow stack switches are protected by a shadow stack restore token that is validated during the switch. Co-authored-by: Nia Su --- sysdeps/unix/sysv/linux/riscv/getcontext.S | 20 +++++ sysdeps/unix/sysv/linux/riscv/makecontext.c | 19 +++++ sysdeps/unix/sysv/linux/riscv/setcontext.S | 67 ++++++++++++++++ sysdeps/unix/sysv/linux/riscv/swapcontext.S | 81 +++++++++++++++++++- sysdeps/unix/sysv/linux/riscv/ucontext_i.sym | 4 +- 5 files changed, 189 insertions(+), 2 deletions(-) diff --git a/sysdeps/unix/sysv/linux/riscv/getcontext.S b/sysdeps/unix/sysv/linux/riscv/getcontext.S index fd55c3e7da..ff1512c2aa 100644 --- a/sysdeps/unix/sysv/linux/riscv/getcontext.S +++ b/sysdeps/unix/sysv/linux/riscv/getcontext.S @@ -17,11 +17,13 @@ . */ #include "ucontext-macros.h" +#include "tcb-offsets.h" /* int getcontext (ucontext_t *ucp) */ .text LEAF (__getcontext) + LPAD SAVE_INT_REG (ra, 0, a0) SAVE_INT_REG (ra, 1, a0) SAVE_INT_REG (sp, 2, a0) @@ -58,6 +60,24 @@ LEAF (__getcontext) sw a1, MCONTEXT_FSR(a0) #endif /* __riscv_float_abi_soft */ +#ifdef __riscv_shadow_stack + ssrdp t0 + beqz t0, .Lskip_ss + /* Read ssp_base from TLS */ + REG_L t1, TLS_SSP_BASE_OFFSET(tp) + + bnez t1, .Lbase_saved + /* if not found, save and use current ssp as the marker */ + mv t1, t0 + REG_S t1, TLS_SSP_BASE_OFFSET(tp) + +.Lbase_saved: + /* Save caller's ssp and base marker to ucontext */ + REG_S t1, UCONTEXT_SSP_BASE(a0) + REG_S t0, UCONTEXT_SSP(a0) +.Lskip_ss: +#endif + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ li a3, _NSIG8 add a2, a0, UCONTEXT_SIGMASK diff --git a/sysdeps/unix/sysv/linux/riscv/makecontext.c b/sysdeps/unix/sysv/linux/riscv/makecontext.c index 7f8ab46bd0..37c922c440 100644 --- a/sysdeps/unix/sysv/linux/riscv/makecontext.c +++ b/sysdeps/unix/sysv/linux/riscv/makecontext.c @@ -21,6 +21,9 @@ #include #include #include +#ifdef __riscv_shadow_stack +#include +#endif void __makecontext (ucontext_t *ucp, void (*func) (void), int argc, @@ -73,6 +76,22 @@ __makecontext (ucontext_t *ucp, void (*func) (void), int argc, va_end (vl); } +#ifdef __riscv_shadow_stack + /* Allocate shadow stack for the new context */ + + /* shstk_size[0]: shadow stack base + shstk_size[1]: shadow stack size */ + shadow_stack_size_t shstk_size[2]; + int ret = __allocate_shadow_stack(ucp->uc_stack.ss_size, shstk_size); + if (ret != 0) + { + abort(); + } + + ucp->__saved.__ssp_base = shstk_size[0]; + ucp->__saved.__ssp = shstk_size[0] + shstk_size[1] - \ + sizeof (shstk_size[0]); +#endif } weak_alias (__makecontext, makecontext) diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S index 9fd5f1f3cb..34ee34b607 100644 --- a/sysdeps/unix/sysv/linux/riscv/setcontext.S +++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S @@ -17,6 +17,7 @@ . */ #include "ucontext-macros.h" +#include "tcb-offsets.h" /* int __setcontext (const ucontext_t *ucp) @@ -29,6 +30,7 @@ .text LEAF (__setcontext) + LPAD mv t0, a0 /* Save ucp into t0. */ @@ -45,6 +47,55 @@ LEAF (__setcontext) cfi_def_cfa (t0, 0) +#ifdef __riscv_shadow_stack + /* Skip if shadow stack is not enabled */ + ssrdp ra + beqz ra, .Lfin + /* We are safe to adjust shadow stack after the sanity check */ + REG_L t1, UCONTEXT_SSP_BASE(t0) + REG_L a1, UCONTEXT_SSP(t0) + REG_L a2, TLS_SSP_BASE_OFFSET(tp) + bne t1, a2, .Ldifferent_stack + +.Lunwind: + bleu a1, 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 = (a1 - ra >= 4096) ? ra + 4096 : a1 */ + lui t2, 1 + add ra, ra, t2 + bleu ra, a1, 1f + mv ra, a1 +1: + csrw ssp, ra + /* Test if the location pointed by ssp is legal */ + sspush ra + sspopchk ra + j .Lunwind + +.Ldifferent_stack: + /* Create restore token */ + sspush ra + mv a4, a1 + +.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, a1 + REG_S t1, TLS_SSP_BASE_OFFSET(tp) +.Lfin: +#endif + #ifndef __riscv_float_abi_soft lw t1, MCONTEXT_FSR(t0) @@ -66,7 +117,11 @@ LEAF (__setcontext) /* Note the contents of argument registers will be random unless makecontext() has been called. */ +#ifdef __riscv_landing_pad + RESTORE_INT_REG (t2, 0, t0) +#else RESTORE_INT_REG (t1, 0, t0) +#endif RESTORE_INT_REG_CFI (ra, 1, t0) RESTORE_INT_REG (sp, 2, t0) RESTORE_INT_REG_CFI (s0, 8, t0) @@ -90,7 +145,12 @@ LEAF (__setcontext) RESTORE_INT_REG_CFI (s10, 26, t0) RESTORE_INT_REG_CFI (s11, 27, t0) +#ifdef __riscv_landing_pad + /* We need to use software-guared jump */ + jr t2 +#else jr t1 +#endif 99: tail __syscall_error @@ -99,12 +159,19 @@ libc_hidden_def (__setcontext) weak_alias (__setcontext, setcontext) LEAF (__start_context) + LPAD /* Terminate call stack by noting ra == 0. Happily, s0 == 0 here. */ cfi_register (ra, s0) /* Call the function passed to makecontext. */ +#ifdef __riscv_landing_pad + /* We need to use software-guared jump */ + mv t2, s1 + jalr t2 +#else jalr s1 +#endif /* Invoke subsequent context if present, else exit(0). */ mv a0, s2 diff --git a/sysdeps/unix/sysv/linux/riscv/swapcontext.S b/sysdeps/unix/sysv/linux/riscv/swapcontext.S index 4b3b0b3a14..a040de1b9a 100644 --- a/sysdeps/unix/sysv/linux/riscv/swapcontext.S +++ b/sysdeps/unix/sysv/linux/riscv/swapcontext.S @@ -17,10 +17,12 @@ . */ #include "ucontext-macros.h" +#include "tcb-offsets.h" /* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */ LEAF (__swapcontext) + LPAD mv t0, a1 /* Save ucp into t0. */ SAVE_INT_REG (ra, 0, a0) @@ -59,6 +61,26 @@ LEAF (__swapcontext) sw a1, MCONTEXT_FSR(a0) #endif /* __riscv_float_abi_soft */ +#ifdef __riscv_shadow_stack + /* Skip if shadow stack is not enabled */ + ssrdp ra + beqz ra, .Lsave_fin + + /* 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, ra + REG_S t2, TLS_SSP_BASE_OFFSET(tp) + +.Lbase_saved: + /* Save caller's ssp and base marker to oucp */ + REG_S t2, UCONTEXT_SSP_BASE(a0) + REG_S ra, UCONTEXT_SSP(a0) +.Lsave_fin: +#endif + /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, _NSIG8) */ li a3, _NSIG8 add a2, a0, UCONTEXT_SIGMASK @@ -70,6 +92,55 @@ LEAF (__swapcontext) bltz a0, 99f +#ifdef __riscv_shadow_stack + /* Skip if shadow stack is not enabled */ + ssrdp ra + beqz ra, .Lfin + /* Load ss information from ucp */ + REG_L a0, UCONTEXT_SSP_BASE(t0) + REG_L a1, UCONTEXT_SSP(t0) + REG_L a2, TLS_SSP_BASE_OFFSET(tp) + bne a0, a2, .Ldifferent_stack + +.Lunwind: + bleu a1, 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 = (a1 - ra >= 4096) ? ra + 4096 : a1 */ + lui t2, 1 + add ra, ra, t2 + bleu ra, a1, 1f + mv ra, a1 +1: + csrw ssp, ra + /* Test if the location pointed by ssp is legal */ + sspush ra + sspopchk ra + j .Lunwind + +.Ldifferent_stack: + /* Create restore token */ + sspush ra + mv a4, a1 + +.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, a1 + REG_S a0, TLS_SSP_BASE_OFFSET(tp) +.Lfin: +#endif + #ifndef __riscv_float_abi_soft lw t1, MCONTEXT_FSR(t0) @@ -91,7 +162,11 @@ LEAF (__swapcontext) /* Note the contents of argument registers will be random unless makecontext() has been called. */ +#ifdef __riscv_landing_pad + RESTORE_INT_REG (t2, 0, t0) +#else RESTORE_INT_REG (t1, 0, t0) +#endif RESTORE_INT_REG (ra, 1, t0) RESTORE_INT_REG (sp, 2, t0) RESTORE_INT_REG (s0, 8, t0) @@ -115,8 +190,12 @@ LEAF (__swapcontext) RESTORE_INT_REG (s10, 26, t0) RESTORE_INT_REG (s11, 27, t0) +#ifdef __riscv_landing_pad + /* We need to use software-guared jump */ + jr t2 +#else jr t1 - +#endif 99: tail __syscall_error diff --git a/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym b/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym index be55b26310..9a39f761ad 100644 --- a/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym +++ b/sysdeps/unix/sysv/linux/riscv/ucontext_i.sym @@ -19,7 +19,9 @@ UCONTEXT_FLAGS ucontext (__uc_flags) UCONTEXT_LINK ucontext (uc_link) UCONTEXT_STACK ucontext (uc_stack) UCONTEXT_MCONTEXT ucontext (uc_mcontext) -UCONTEXT_SIGMASK ucontext (uc_sigmask) +UCONTEXT_SIGMASK ucontext (__saved.__saved_mask) +UCONTEXT_SSP ucontext (__saved.__ssp) +UCONTEXT_SSP_BASE ucontext (__saved.__ssp_base) STACK_SP stack (ss_sp) STACK_SIZE stack (ss_size)