From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4AB68C54ED0 for ; Fri, 23 May 2025 05:32:13 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id DA26C6B00B0; Fri, 23 May 2025 01:32:12 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id D52526B00B1; Fri, 23 May 2025 01:32:12 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id BF37A6B00B2; Fri, 23 May 2025 01:32:12 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 9A7FA6B00B0 for ; Fri, 23 May 2025 01:32:12 -0400 (EDT) Received: from smtpin16.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 54F471D47B6 for ; Fri, 23 May 2025 05:32:12 +0000 (UTC) X-FDA: 83473051704.16.E7ABB31 Received: from mail-pf1-f176.google.com (mail-pf1-f176.google.com [209.85.210.176]) by imf14.hostedemail.com (Postfix) with ESMTP id 58933100005 for ; Fri, 23 May 2025 05:32:10 +0000 (UTC) Authentication-Results: imf14.hostedemail.com; dkim=pass header.d=rivosinc-com.20230601.gappssmtp.com header.s=20230601 header.b=PKLXLJSV; spf=pass (imf14.hostedemail.com: domain of debug@rivosinc.com designates 209.85.210.176 as permitted sender) smtp.mailfrom=debug@rivosinc.com; dmarc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1747978330; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=5J/5mZxT+k+LmAKU7G8MkVD/8s7ODhQZCUl5WVjl9l4=; b=Lm7lpA7DDiY6xvdm5bw/QP0KSFYiZX++Sob6gBF6TbzgJPSOitFyi2s1/SYFtnwiMfWGde pDxUTStczCUTXXPKOVs3FlRKs44fgqrZiZ9ZzVzU9xhbMCvMhwwav8ScN6321PR15Y9bqN e5Z//FUSwbgGdeHNf3llJigXVNvuWPo= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1747978330; a=rsa-sha256; cv=none; b=dl3EO86fSsHDW3GvLqkWVm/ANc2RiF47+9LfxaWUvVyWvXl04u8TFoDLZJ/xeQqIp897Ej dRgvtXtNztad9F6GHlZz15W3Q3lLnpe2//bWkomTUTfJ9lQVMGPvjQ3a1Y8jEcBc5vz3qc GvPCW1305k0zE2VbfxTtfDXckE5/Cic= ARC-Authentication-Results: i=1; imf14.hostedemail.com; dkim=pass header.d=rivosinc-com.20230601.gappssmtp.com header.s=20230601 header.b=PKLXLJSV; spf=pass (imf14.hostedemail.com: domain of debug@rivosinc.com designates 209.85.210.176 as permitted sender) smtp.mailfrom=debug@rivosinc.com; dmarc=none Received: by mail-pf1-f176.google.com with SMTP id d2e1a72fcca58-73c17c770a7so9343867b3a.2 for ; Thu, 22 May 2025 22:32:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1747978329; x=1748583129; darn=kvack.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=5J/5mZxT+k+LmAKU7G8MkVD/8s7ODhQZCUl5WVjl9l4=; b=PKLXLJSVg/+8kG2Q4scOQ2TUE1OiDQzwKsIRV2TNnciTYa9+iJ5YlCxYwLKsbH8Q4Q LE8tBEHjUr/cEVZ2+8pkrsrOvxktyfYOQMSWPNLPHlVXo/mfhehGtS0qyQBpGKN3HlGM RkNaRVK/hp77xGrk5iV6FBQYA+F73CPD/VXWyWxWC7x7c0AdIS3nlmEBX9rw2eEHy7TT pRx/4Kxz4iC+PgUFsnKHKGanqhG1UL3TOobg3L2sx0WPzGMrFQdrAMYhcBfJTq0j7RPa 0jDucRSmAOQSdke0kRv7f7AGsJnTqwpc+Un2+84JvKhuE488wuV/m7pzWJsVeKYpgyrT WWcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1747978329; x=1748583129; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=5J/5mZxT+k+LmAKU7G8MkVD/8s7ODhQZCUl5WVjl9l4=; b=JyWjIyMZzLwH4JTOspnBF+1qpeuTs0EER73BzIPaP5vgBbyvL02K37/Hzv2bNB8e/z B7x7SZzr2zHDE4lgmD80A1+jB1y0o9c69DmwemsvTGDwCQL0eED6jYIIgIwFLbIaQAyK ockAp01BlEGRJJ+x7En6BDAQp/TMJqFgEdhXadsWQbyYAfHr//11OYi8he4oG/zZ3ad4 oDIrYLOBX0PN9gC+OrGUdwudljFDn6/0DxoP2QoInApceVT7BUbj1+euliQCkpMGq1aw +K38/pu8Py8qpvVhUelHToPV0ci/YyIIhZMjm2rP7h+M1cA2R0kJgXs7k++zSy3un8u3 q7LA== X-Forwarded-Encrypted: i=1; AJvYcCVKtjthPWCXnKpuSgAIMp8F12Zqq+zDj4QoKH5diebT+rQI/fXXobdqYloqbboJ58T1rBWBMtpqXA==@kvack.org X-Gm-Message-State: AOJu0Yz7Ow9SBVLpEd/+OuyKIf/LLZdvj2klI6y7Ak4r2MUsaFSQ1aQQ 1doez1Dr58rKGTyIswpCk5SKpPy3iAJDTnaOpAXJ2SlNyarkpt9MewppnncXv4Lc/o8= X-Gm-Gg: ASbGncs0VL/jxZkMwf1czwnQJh2HZIl+Yu2G7QGf3+5NTnI4vwkvJ6Dyc/wESMaDnKU Xh09+yw04TIBu9JWkf996gWkejud8XXHjPOlbfjkQMtN/wGRRAO/vgRgCvkTCfVfjsGzB8LVs/6 RJVs35ob+PTC+qTe6ZauhbOuvX4JOziq0ybKxREVXs9foFry8cxkHq+fXhxAxxekAfOpYhCx+Dw xzpIqz7KhKi/CB8IhVyWLOd0MDcUXhP5HE6VHuuxcStEmb7vSbbaMzAJAB10N9cQiNTml1HxOfd F8tq7bbfnYztHEaMHKpfb5Z2MS0WGB9K/qIDp4W3NmyOj9ElUdjjmHhCk0WYpA== X-Google-Smtp-Source: AGHT+IFyQuepg0hzZeCt1JntR2Wsb/feeKyMOrKezkULGdABKI1cAeVktT5QjCly+fai6r+PK6/nKw== X-Received: by 2002:a05:6a00:92a3:b0:742:a02e:dd8f with SMTP id d2e1a72fcca58-745ed9090f2mr2099941b3a.22.1747978329098; Thu, 22 May 2025 22:32:09 -0700 (PDT) Received: from debug.ba.rivosinc.com ([64.71.180.162]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-742a982a0a4sm12474336b3a.101.2025.05.22.22.32.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 22 May 2025 22:32:08 -0700 (PDT) From: Deepak Gupta Date: Thu, 22 May 2025 22:31:20 -0700 Subject: [PATCH v16 17/27] riscv/signal: save and restore of shadow stack for signal MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20250522-v5_user_cfi_series-v16-17-64f61a35eee7@rivosinc.com> References: <20250522-v5_user_cfi_series-v16-0-64f61a35eee7@rivosinc.com> In-Reply-To: <20250522-v5_user_cfi_series-v16-0-64f61a35eee7@rivosinc.com> To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Andrew Morton , "Liam R. Howlett" , Vlastimil Babka , Lorenzo Stoakes , Paul Walmsley , Palmer Dabbelt , Albert Ou , Conor Dooley , Rob Herring , Krzysztof Kozlowski , Arnd Bergmann , Christian Brauner , Peter Zijlstra , Oleg Nesterov , Eric Biederman , Kees Cook , Jonathan Corbet , Shuah Khan , Jann Horn , Conor Dooley , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, linux-arch@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, alistair.francis@wdc.com, richard.henderson@linaro.org, jim.shu@sifive.com, andybnac@gmail.com, kito.cheng@sifive.com, charlie@rivosinc.com, atishp@rivosinc.com, evan@rivosinc.com, cleger@rivosinc.com, alexghiti@rivosinc.com, samitolvanen@google.com, broonie@kernel.org, rick.p.edgecombe@intel.com, rust-for-linux@vger.kernel.org, Deepak Gupta , Andy Chiu X-Mailer: b4 0.13.0 X-Rspamd-Server: rspam06 X-Rspamd-Queue-Id: 58933100005 X-Stat-Signature: ek5jph78oie8o6meak48p6ujhfcw3giq X-Rspam-User: X-HE-Tag: 1747978330-24234 X-HE-Meta: U2FsdGVkX18uoCpPJC5wx0ubQf+HXakXMh5HzhV1ja5UYG4XGV8w6Aow+jDK0WIQid+2Kj4HF5mRwVg+D/j5pjg0o5ZzlDH4KzmKbMawPuXNRWrcvrRTIyes07U/lLjUM6Dww05m/LsD/kHRFePYq9gLmpiD/nasXGoqeDqQGKYEgrB35NA/FGBiv5f+M396ieFoE3vTOwlwonuGRHLstYFBSdfqgSnOj29rXMnz6R+QIw9vygAWbtsxXKo85FCSNvk9M20puww+OHOdiTRb9J0xAYqwotqXSA0sJSgLrd9FcQmmE7N1KFCjjqt+nEGMV80Uvm61DObdjtWjxNUZSPz3iM2SNrxcKvUJumSrwu23hrETce6AjqTcViitWvC40+Cesc0BgfaIajnz5XkV4E/9+IfPdGGDmCzqTt/en+nXmuz64FhuaOCw9X9+Hk3TRCg2Vh5+K9qUqahv1jYepjKEm8jEOzPc3h5t8tdXxQYcvtP5lB/MnvB6e2oSzfmNTWi9bgqoXYQzDFLy/uzRonNqSCHA+5KgmrMY8eyPFjh8EgXwIPPEQCgpH9896b4ooEX6/zoGcD6uowqQgPBVJq/RicvnI/kn0VhRQz9I1E0GXU0Xjwv89EibDlZuBA0u/IIfdgNyDWwcvwvrq72Xa3SjeSepdX96yuqZ6lHvRJvttQrCb2Mq6MnAK9z+G6ZU5SuqYVpNLWC2OuZf8Td/D4or9Jt1LgrfPawt8XVSeePoKIfa1D2nMIYzIDLiA2Va0LK15+83MtjRNLVVLQYXGDwa1xoYNiOIacP0Nb5cR159Z44gD24UKatTcRmcMZY+n8SNkrNL+8TbsP79182U1wg/FzKkGsrNSdj8hK9Rg0oLc9IoatEqK2DnzbtQtzb64QQ7Llb69/a9hG/DU2LboPH/DvemNhQ0Wx6rpR8477LX66t8rFfxU3YbA+pKxbl2N+w0dkHERCULqE4JxI9 e6UyevmZ BN5s6AGDsAzZ6JlqGXvigERiOJduRz3+y3VvSsrr+YGNrRQtjbapL1K8HcFCUW5sxEpzr1X4vuRmFB+GDAllEH+wpHRuQ8v0EDNzARB8Ii21c58/5GUb0PzqxL8KHYEGZOobGr2myZ1i367s1gtvHwfXnn74yemrAs9hoNG6xi+lwkt8WhEYXvsbdVpxJ07ZwoHsoPxLCQDVNzNHE5tr4wjwZLNhHwVerb6hPPjymYnFt2uVLiqsZVNc2Cm24cwfcClerQcv56jadVVCGmiPhE44nQgjFgSBaNMI2FI2iIChYvmxSlRFfKjQqOgUsYoF6vFvYqds6naaf58e6mfgtuxiuRecYgxA9abMqBCGYGavzHY2j1Ul9sRJ3BgttWMc+K46eFOuB/NBGVb4EGlhvrY/KICtiD4TGyryl9FHvIkFUNuLUw+YJj5MhzG9HbCoehTF+lVw8TeBKcqyIcOYNKHdPD+VmkyYxKM6z7g8LsKRfuhFY1dVP+FJAfSVoP4Jbe0gEMQ3497WTocA= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Save shadow stack pointer in sigcontext structure while delivering signal. Restore shadow stack pointer from sigcontext on sigreturn. As part of save operation, kernel uses `ssamoswap` to save snapshot of current shadow stack on shadow stack itself (can be called as a save token). During restore on sigreturn, kernel retrieves token from top of shadow stack and validates it. This allows that user mode can't arbitrary pivot to any shadow stack address without having a token and thus provide strong security assurance between signaly delivery and sigreturn window. Use ABI compatible way of saving/restoring shadow stack pointer into signal stack. This follows what Vector extension, where extra registers are placed in a form of extension header + extension body in the stack. The extension header indicates the size of the extra architectural states plus the size of header itself, and a magic identifier of the extension. Then, the extensions body contains the new architectural states in the form defined by uapi. Signed-off-by: Andy Chiu Signed-off-by: Deepak Gupta --- arch/riscv/include/asm/usercfi.h | 10 ++++ arch/riscv/include/uapi/asm/ptrace.h | 4 ++ arch/riscv/include/uapi/asm/sigcontext.h | 1 + arch/riscv/kernel/signal.c | 86 ++++++++++++++++++++++++++++++++ arch/riscv/kernel/usercfi.c | 56 +++++++++++++++++++++ 5 files changed, 157 insertions(+) diff --git a/arch/riscv/include/asm/usercfi.h b/arch/riscv/include/asm/usercfi.h index cea7908cdb3a..68da5b7b79fd 100644 --- a/arch/riscv/include/asm/usercfi.h +++ b/arch/riscv/include/asm/usercfi.h @@ -8,6 +8,7 @@ #ifndef __ASSEMBLY__ #include #include +#include struct task_struct; struct kernel_clone_args; @@ -34,6 +35,9 @@ bool is_shstk_locked(struct task_struct *task); bool is_shstk_allocated(struct task_struct *task); void set_shstk_lock(struct task_struct *task); void set_shstk_status(struct task_struct *task, bool enable); +unsigned long get_active_shstk(struct task_struct *task); +int restore_user_shstk(struct task_struct *tsk, unsigned long shstk_ptr); +int save_user_shstk(struct task_struct *tsk, unsigned long *saved_shstk_ptr); bool is_indir_lp_enabled(struct task_struct *task); bool is_indir_lp_locked(struct task_struct *task); void set_indir_lp_status(struct task_struct *task, bool enable); @@ -71,6 +75,12 @@ void set_indir_lp_lock(struct task_struct *task); #define set_indir_lp_lock(task) +#define restore_user_shstk(tsk, shstk_ptr) -EINVAL + +#define save_user_shstk(tsk, saved_shstk_ptr) -EINVAL + +#define get_active_shstk(task) 0UL + #endif /* CONFIG_RISCV_USER_CFI */ #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/include/uapi/asm/ptrace.h b/arch/riscv/include/uapi/asm/ptrace.h index a38268b19c3d..659ea3af5680 100644 --- a/arch/riscv/include/uapi/asm/ptrace.h +++ b/arch/riscv/include/uapi/asm/ptrace.h @@ -127,6 +127,10 @@ struct __riscv_v_regset_state { */ #define RISCV_MAX_VLENB (8192) +struct __sc_riscv_cfi_state { + unsigned long ss_ptr; /* shadow stack pointer */ +}; + #endif /* __ASSEMBLY__ */ #endif /* _UAPI_ASM_RISCV_PTRACE_H */ diff --git a/arch/riscv/include/uapi/asm/sigcontext.h b/arch/riscv/include/uapi/asm/sigcontext.h index cd4f175dc837..f37e4beffe03 100644 --- a/arch/riscv/include/uapi/asm/sigcontext.h +++ b/arch/riscv/include/uapi/asm/sigcontext.h @@ -10,6 +10,7 @@ /* The Magic number for signal context frame header. */ #define RISCV_V_MAGIC 0x53465457 +#define RISCV_ZICFISS_MAGIC 0x9487 #define END_MAGIC 0x0 /* The size of END signal context header. */ diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index a5e3d54fe54b..1bcda11e0680 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -22,11 +22,13 @@ #include #include #include +#include unsigned long signal_minsigstksz __ro_after_init; extern u32 __user_rt_sigreturn[2]; static size_t riscv_v_sc_size __ro_after_init; +static size_t riscv_zicfiss_sc_size __ro_after_init; #define DEBUG_SIG 0 @@ -140,6 +142,62 @@ static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec) return copy_from_user(current->thread.vstate.datap, datap, riscv_v_vsize); } +static long save_cfiss_state(struct pt_regs *regs, void __user *sc_cfi) +{ + struct __sc_riscv_cfi_state __user *state = sc_cfi; + unsigned long ss_ptr = 0; + long err = 0; + + if (!is_shstk_enabled(current)) + return 0; + + /* + * Save a pointer to shadow stack itself on shadow stack as a form of token. + * A token on shadow gives following properties + * - Safe save and restore for shadow stack switching. Any save of shadow stack + * must have had saved a token on shadow stack. Similarly any restore of shadow + * stack must check the token before restore. Since writing to shadow stack with + * address of shadow stack itself is not easily allowed. A restore without a save + * is quite difficult for an attacker to perform. + * - A natural break. A token in shadow stack provides a natural break in shadow stack + * So a single linear range can be bucketed into different shadow stack segments. Any + * sspopchk will detect the condition and fault to kernel as sw check exception. + */ + err |= save_user_shstk(current, &ss_ptr); + err |= __put_user(ss_ptr, &state->ss_ptr); + if (unlikely(err)) + return -EFAULT; + + return riscv_zicfiss_sc_size; +} + +static long __restore_cfiss_state(struct pt_regs *regs, void __user *sc_cfi) +{ + struct __sc_riscv_cfi_state __user *state = sc_cfi; + unsigned long ss_ptr = 0; + long err; + + /* + * Restore shadow stack as a form of token stored on shadow stack itself as a safe + * way to restore. + * A token on shadow gives following properties + * - Safe save and restore for shadow stack switching. Any save of shadow stack + * must have had saved a token on shadow stack. Similarly any restore of shadow + * stack must check the token before restore. Since writing to shadow stack with + * address of shadow stack itself is not easily allowed. A restore without a save + * is quite difficult for an attacker to perform. + * - A natural break. A token in shadow stack provides a natural break in shadow stack + * So a single linear range can be bucketed into different shadow stack segments. + * sspopchk will detect the condition and fault to kernel as sw check exception. + */ + err = __copy_from_user(&ss_ptr, &state->ss_ptr, sizeof(unsigned long)); + + if (unlikely(err)) + return err; + + return restore_user_shstk(current, ss_ptr); +} + struct arch_ext_priv { __u32 magic; long (*save)(struct pt_regs *regs, void __user *sc_vec); @@ -150,6 +208,10 @@ struct arch_ext_priv arch_ext_list[] = { .magic = RISCV_V_MAGIC, .save = &save_v_state, }, + { + .magic = RISCV_ZICFISS_MAGIC, + .save = &save_cfiss_state, + }, }; const size_t nr_arch_exts = ARRAY_SIZE(arch_ext_list); @@ -202,6 +264,12 @@ static long restore_sigcontext(struct pt_regs *regs, err = __restore_v_state(regs, sc_ext_ptr); break; + case RISCV_ZICFISS_MAGIC: + if (!is_shstk_enabled(current) || size != riscv_zicfiss_sc_size) + return -EINVAL; + + err = __restore_cfiss_state(regs, sc_ext_ptr); + break; default: return -EINVAL; } @@ -223,6 +291,16 @@ static size_t get_rt_frame_size(bool cal_all) total_context_size += riscv_v_sc_size; } + if (is_shstk_enabled(current)) + total_context_size += riscv_zicfiss_sc_size; + + /* + * Preserved a __riscv_ctx_hdr for END signal context header if an + * extension uses __riscv_extra_ext_header + */ + if (total_context_size) + total_context_size += sizeof(struct __riscv_ctx_hdr); + frame_size += total_context_size; frame_size = round_up(frame_size, 16); @@ -359,6 +437,11 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, #ifdef CONFIG_MMU regs->ra = (unsigned long)VDSO_SYMBOL( current->mm->context.vdso, rt_sigreturn); + + /* if bcfi is enabled x1 (ra) and x5 (t0) must match. not sure if we need this? */ + if (is_shstk_enabled(current)) + regs->t0 = regs->ra; + #else /* * For the nommu case we don't have a VDSO. Instead we push two @@ -487,6 +570,9 @@ void __init init_rt_signal_env(void) { riscv_v_sc_size = sizeof(struct __riscv_ctx_hdr) + sizeof(struct __sc_riscv_v_state) + riscv_v_vsize; + + riscv_zicfiss_sc_size = sizeof(struct __riscv_ctx_hdr) + + sizeof(struct __sc_riscv_cfi_state); /* * Determine the stack space required for guaranteed signal delivery. * The signal_minsigstksz will be populated into the AT_MINSIGSTKSZ entry diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c index 2ebe789caa6b..8bc3e1e3f712 100644 --- a/arch/riscv/kernel/usercfi.c +++ b/arch/riscv/kernel/usercfi.c @@ -52,6 +52,11 @@ void set_active_shstk(struct task_struct *task, unsigned long shstk_addr) task->thread_info.user_cfi_state.user_shdw_stk = shstk_addr; } +unsigned long get_active_shstk(struct task_struct *task) +{ + return task->thread_info.user_cfi_state.user_shdw_stk; +} + void set_shstk_status(struct task_struct *task, bool enable) { if (!cpu_supports_shadow_stack()) @@ -169,6 +174,57 @@ static int create_rstor_token(unsigned long ssp, unsigned long *token_addr) return 0; } +/* + * Save user shadow stack pointer on shadow stack itself and return pointer to saved location + * returns -EFAULT if operation was unsuccessful + */ +int save_user_shstk(struct task_struct *tsk, unsigned long *saved_shstk_ptr) +{ + unsigned long ss_ptr = 0; + unsigned long token_loc = 0; + int ret = 0; + + if (saved_shstk_ptr == NULL) + return -EINVAL; + + ss_ptr = get_active_shstk(tsk); + ret = create_rstor_token(ss_ptr, &token_loc); + + if (!ret) { + *saved_shstk_ptr = token_loc; + set_active_shstk(tsk, token_loc); + } + + return ret; +} + +/* + * Restores user shadow stack pointer from token on shadow stack for task `tsk` + * returns -EFAULT if operation was unsuccessful + */ +int restore_user_shstk(struct task_struct *tsk, unsigned long shstk_ptr) +{ + unsigned long token = 0; + + token = amo_user_shstk((unsigned long __user *)shstk_ptr, 0); + + if (token == -1) + return -EFAULT; + + /* invalid token, return EINVAL */ + if ((token - shstk_ptr) != SHSTK_ENTRY_SIZE) { + pr_info_ratelimited( + "%s[%d]: bad restore token in %s: pc=%p sp=%p, token=%p, shstk_ptr=%p\n", + tsk->comm, task_pid_nr(tsk), __func__, (void *)(task_pt_regs(tsk)->epc), + (void *)(task_pt_regs(tsk)->sp), (void *)token, (void *)shstk_ptr); + return -EINVAL; + } + + /* all checks passed, set active shstk and return success */ + set_active_shstk(tsk, token); + return 0; +} + static unsigned long allocate_shadow_stack(unsigned long addr, unsigned long size, unsigned long token_offset, bool set_tok) { -- 2.43.0