From patchwork Wed Apr 3 23:35:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Deepak Gupta X-Patchwork-Id: 13616818 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 2A621CD128A for ; Wed, 3 Apr 2024 23:42:44 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 2658E8D0003; Wed, 3 Apr 2024 19:42:43 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 1E1868D0001; Wed, 3 Apr 2024 19:42:42 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id D2DC18D0003; Wed, 3 Apr 2024 19:42:42 -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 A42988D0001 for ; Wed, 3 Apr 2024 19:42:42 -0400 (EDT) Received: from smtpin04.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 63E0F140785 for ; Wed, 3 Apr 2024 23:42:42 +0000 (UTC) X-FDA: 81969847764.04.AB1130E Received: from mail-pl1-f172.google.com (mail-pl1-f172.google.com [209.85.214.172]) by imf17.hostedemail.com (Postfix) with ESMTP id 8B7E94000E for ; Wed, 3 Apr 2024 23:42:40 +0000 (UTC) Authentication-Results: imf17.hostedemail.com; dkim=pass header.d=rivosinc-com.20230601.gappssmtp.com header.s=20230601 header.b=1iZ1zIEE; dmarc=none; spf=pass (imf17.hostedemail.com: domain of debug@rivosinc.com designates 209.85.214.172 as permitted sender) smtp.mailfrom=debug@rivosinc.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1712187760; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=Khz8ikyQpN700q+teRby/p+dyzEQ886SCy2AoWH5oD0=; b=JZMqv8xG/HFiAQSRTETRB+sn2HjGBqc1ngKu+URxFVvtOhmimQlZvLaCbBlJPLIkQlruO6 FeS9A5q07iVrBotHz+Vr3iBlP175Wh8s7FquZEQRhaPULgb2kR7INhhd18/D5vOAPhdrPy vOf/3uxfYSiC0XEHfO4ZfxXO3Myp9II= ARC-Authentication-Results: i=1; imf17.hostedemail.com; dkim=pass header.d=rivosinc-com.20230601.gappssmtp.com header.s=20230601 header.b=1iZ1zIEE; dmarc=none; spf=pass (imf17.hostedemail.com: domain of debug@rivosinc.com designates 209.85.214.172 as permitted sender) smtp.mailfrom=debug@rivosinc.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1712187760; a=rsa-sha256; cv=none; b=sIM9ygAPAYWmx+2pWRaKs3j05MxI93Yp/o8E6Gp1+SmfoTljcKiIfOP5oQ04iQ05jZvGg9 Ar1XpwZ1mw4yso0prF92Y0d1CGnKXtQ5C1ZIJi2sHwztswQqXB/pQeFTOTd2gnc+t5UW67 qZ30/7CDXJ1ApPV9QquJa3md+TtbPg0= Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-1e252f2bf23so3149055ad.2 for ; Wed, 03 Apr 2024 16:42:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20230601.gappssmtp.com; s=20230601; t=1712187759; x=1712792559; darn=kvack.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=Khz8ikyQpN700q+teRby/p+dyzEQ886SCy2AoWH5oD0=; b=1iZ1zIEEf7NkhihLgkw54c+e+G20FEmiLd2lWRfzKcxknJZs2qkKGaCWc1BkN9CM8g xQ3b+NvJ+5T94vm+GozV2DzR/5rhXVmdOUCDlfoLVLY/ajgvgVBjti2mONriAYxoujDG Erq6Ue1jOXOvL2jTpdq9Yhpq2Kx9WqXKmj69P2ozBFtZrno8/HV1bIgOxZ773QZVKqd8 w22B/4z0ZkS8lSEfpf8O8jhAuAbQ9OyHYO6epDWQ/6UM+mKKiQTCcqkyVf7s7Phh00S7 rNP8Mj6gmo1C+jYi+yzj2Z+d3zpupDJ4zJWChBBvEFppxuKOvkhbdA0v6FUDZtiv85Yc rV+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712187759; x=1712792559; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Khz8ikyQpN700q+teRby/p+dyzEQ886SCy2AoWH5oD0=; b=DnN5m9grXL8j3xBVt8Pf/9xy6i+kheW3xNXiDVsEdh2Df/V6USzQ06eKNflOVHNG8Q BJD+JKfX40rgyRwRJbN6chd1WYxdw4rQ+JIqvUdht+vzZ4WSH+26R0DEQoi/tFWnobUV M91XYJThA+W58pXOXwZ8fTFHw5lSkWCtKyZ4k8Txbd188OlReh0EkoqANpa6wi8iOUwr M8OcoQnFtEMBo3ppsUSdnQpQcbbnz3C5hVhp9gGsWs4YslhV6E7w+WuguqfcdsTOco5p 6DsZxTGGegP7Xkc6Z96yIU6fAnSDJgDb19+UizGdUbWoP4ltev/fU9CJ1yQKjvlxQ8r5 rMXA== X-Forwarded-Encrypted: i=1; AJvYcCWX7TBug+v8YdkcDFQ+x8uenBxPE4h6As3kveolz8cTOKOK22LeXc/43Tx9V8VnWwAWN97eCiZF6/n7SEBO7eGVjck= X-Gm-Message-State: AOJu0YyGrxGG0dQ1NK97L5P3h0c7qLS+mE9XVBl+xLBOlAbsNIB4yYPa rLFKvsGld8SUNTbwG/g0hfhnaKk/oH06EzXADzDi9MvNAFmJVjxI4hhqIrl4a8A= X-Google-Smtp-Source: AGHT+IE68qWmATPhXV1Rat+Ver9WaYarHZF7n/8/iZq8gRLxh8kCGb8Ckpz5WZ6DY6GOuSzrKLE5Sg== X-Received: by 2002:a17:902:e5d2:b0:1dd:c288:899f with SMTP id u18-20020a170902e5d200b001ddc288899fmr843683plf.18.1712187759354; Wed, 03 Apr 2024 16:42:39 -0700 (PDT) Received: from debug.ba.rivosinc.com ([64.71.180.162]) by smtp.gmail.com with ESMTPSA id b18-20020a170902d51200b001deeac592absm13899117plg.180.2024.04.03.16.42.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Apr 2024 16:42:38 -0700 (PDT) From: Deepak Gupta To: paul.walmsley@sifive.com, rick.p.edgecombe@intel.com, broonie@kernel.org, Szabolcs.Nagy@arm.com, kito.cheng@sifive.com, keescook@chromium.org, ajones@ventanamicro.com, conor.dooley@microchip.com, cleger@rivosinc.com, atishp@atishpatra.org, alex@ghiti.fr, bjorn@rivosinc.com, alexghiti@rivosinc.com, samuel.holland@sifive.com, conor@kernel.org Cc: linux-doc@vger.kernel.org, linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-mm@kvack.org, linux-arch@vger.kernel.org, linux-kselftest@vger.kernel.org, corbet@lwn.net, palmer@dabbelt.com, aou@eecs.berkeley.edu, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, oleg@redhat.com, akpm@linux-foundation.org, arnd@arndb.de, ebiederm@xmission.com, Liam.Howlett@oracle.com, vbabka@suse.cz, lstoakes@gmail.com, shuah@kernel.org, brauner@kernel.org, debug@rivosinc.com, andy.chiu@sifive.com, jerry.shih@sifive.com, hankuan.chen@sifive.com, greentime.hu@sifive.com, evan@rivosinc.com, xiao.w.wang@intel.com, charlie@rivosinc.com, apatel@ventanamicro.com, mchitale@ventanamicro.com, dbarboza@ventanamicro.com, sameo@rivosinc.com, shikemeng@huaweicloud.com, willy@infradead.org, vincent.chen@sifive.com, guoren@kernel.org, samitolvanen@google.com, songshuaishuai@tinylab.org, gerg@kernel.org, heiko@sntech.de, bhe@redhat.com, jeeheng.sia@starfivetech.com, cyy@cyyself.name, maskray@google.com, ancientmodern4@gmail.com, mathis.salmen@matsal.de, cuiyunhui@bytedance.com, bgray@linux.ibm.com, mpe@ellerman.id.au, baruch@tkos.co.il, alx@kernel.org, david@redhat.com, catalin.marinas@arm.com, revest@chromium.org, josh@joshtriplett.org, shr@devkernel.io, deller@gmx.de, omosnace@redhat.com, ojeda@kernel.org, jhubbard@nvidia.com Subject: [PATCH v3 23/29] riscv signal: Save and restore of shadow stack for signal Date: Wed, 3 Apr 2024 16:35:11 -0700 Message-ID: <20240403234054.2020347-24-debug@rivosinc.com> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240403234054.2020347-1-debug@rivosinc.com> References: <20240403234054.2020347-1-debug@rivosinc.com> MIME-Version: 1.0 X-Rspam-User: X-Rspamd-Server: rspam12 X-Rspamd-Queue-Id: 8B7E94000E X-Stat-Signature: 9q3hd9c9uwui3x69ztgyt3bhcr1zczzc X-HE-Tag: 1712187760-328389 X-HE-Meta: U2FsdGVkX1+nQLNlCPnwYw3n5MWMbbrES/aSEz2MFScpRLNbAeq0Aha9mxopPD79nPoEHG8Av0j3kJuC7zCcIBgg9+UcdH9rRkQahGt86jdntp7fXHZUBsJbVSVVkde1SnAZ70AyTXMl7de735MGTyZAz2WGhbbvVzpJgZSUdiLKM0F6rip86YBgunIgnfTVUA8b2Zvs6vfdsZ8B+UinOZY4uq1XmP1Pgbq7NbC0kcAB2689NAHK2NYQBcxCEstmh6HzusduZK5zHcSZHijrcnsh0D5/RFiXbrW1oC4rgatQ3gLBP9pZQHXBt6PBHT+xVMh09X0n5XpCUjbajV/zin6fpIO8SvHPopoMvAU8AaRM8mpkukDpI6FiiZsZN+PrdTERucDyp3n/opFJKzRf5Rst3BfZl3iRwVrf+vWsNt2v1O5kAX9p2dMiIU+HM6CSgrBadMqh3kraUXs9Bs6mIddL5tIGP5PTWIDslF+vAzcP88S7HBmu3aSWArWTELUr015IA1UkI1QoXIPokgVe38Yo2+ZVQYgi41aaWKOvRuAk4W0O2RLefhcOSM4j3mezVklsBEPPa8TL4FoSGmdVt+OkQJ6k9DHK6WkOLeh/ohr0bNwvwi2pjV/ORTIUhAMW/nOiN0adxCaeK1AqsDbnKzHj2JIDRvOSAe0idM46svgmaoPuFa4xlEB/Rv6o/9zi92hVY8v0sRrhTkjGueiLcPEQfFKeR39waUroNR2uynReVZEK6RayFwpmiRlA+OZ7lxgQzrVTz/kByRTDLxEayJK3LUF2mkStamoA77njval7xK1fguwoBoDmCWG+RKdeM2zIAEJaYD9pDoDqyToSYW9wIF2QsvGNqe5OqEKEcB3LcDDhmtd/aWt3SZzK2SvhgN8ndwwFOQWQRwCDR0nQCnWSgMFxO6aeRTZEJy2IMV2D/Stf7HLIXX5r8Z+5XVol3XClNelM7Ksjnb1pGOb Tq6qe0YU bBBTRHATNA4X6T7axb8bKzkhpUe12IKIT+eegE56LdyeFNF0sAjG5gVSJl+9LjQmrfMXfae6b5JdcWh3O0HpWUzZRarTsPtS5Czf9EfiSmOcKU+yfGpCVoRRMeG8qxZrKX+ey6sibaQZaj2S3juLns3Qhq97v3eEnqC5GREPS1bdtx6qrTYFXF7j5tERk1C6ClacFb6sDKpTHSMY3GZ2Qsn+orKHmtT93qshmOaNTW0epcjWXWjn15Rk+CwON9T4uVLcKp2rPtM2MR537UouZXiBWzo+o4caWOWjHGtTUXHgk+bgoZTIP/QqMeSg6wFDEqS/HGyxIBoNhhxlLBZZWqHA2GLUkO9HvzmdZcHWN3C3rO+faLOZKHtStogx+V9f8RZz0se3RxVdwI037guvNmc2KPJtHih+fOMq8Pwr+51LDw5pdr00HifIR9yNSjL7aSF8Dv/U5YAZ1KdkVHvh15T2CzE5u+982GigXx/17KA+SMHz5y+S8glEf1MP5b52wc/8pX9+ys0QTPUU= 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. Signed-off-by: Deepak Gupta --- arch/riscv/include/asm/usercfi.h | 19 +++++++++++ arch/riscv/kernel/signal.c | 45 +++++++++++++++++++++++++ arch/riscv/kernel/usercfi.c | 57 ++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) diff --git a/arch/riscv/include/asm/usercfi.h b/arch/riscv/include/asm/usercfi.h index 8accdc8ec164..507a27d5f53c 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; @@ -35,6 +36,9 @@ void set_shstk_status(struct task_struct *task, bool enable); 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); +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); #define PR_SHADOW_STACK_SUPPORTED_STATUS_MASK (PR_SHADOW_STACK_ENABLE) @@ -77,6 +81,16 @@ static inline void set_shstk_status(struct task_struct *task, bool enable) } +static inline int restore_user_shstk(struct task_struct *tsk, unsigned long shstk_ptr) +{ + return -EINVAL; +} + +static inline int save_user_shstk(struct task_struct *tsk, unsigned long *saved_shstk_ptr) +{ + return -EINVAL; +} + static inline bool is_indir_lp_enabled(struct task_struct *task) { return false; @@ -92,6 +106,11 @@ static inline void set_indir_lp_status(struct task_struct *task, bool enable) } +static inline unsigned long get_active_shstk(struct task_struct *task) +{ + return 0; +} + #endif /* CONFIG_RISCV_USER_CFI */ #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 501e66debf69..428a886ab6ef 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -22,6 +22,7 @@ #include #include #include +#include unsigned long signal_minsigstksz __ro_after_init; @@ -232,6 +233,7 @@ SYSCALL_DEFINE0(rt_sigreturn) struct pt_regs *regs = current_pt_regs(); struct rt_sigframe __user *frame; struct task_struct *task; + unsigned long ss_ptr = 0; sigset_t set; size_t frame_size = get_rt_frame_size(false); @@ -254,6 +256,26 @@ SYSCALL_DEFINE0(rt_sigreturn) if (restore_altstack(&frame->uc.uc_stack)) goto badframe; + /* + * 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. + */ + if (__copy_from_user(&ss_ptr, &frame->uc.uc_mcontext.sc_cfi_state.ss_ptr, + sizeof(unsigned long))) + goto badframe; + + if (is_shstk_enabled(current) && restore_user_shstk(current, ss_ptr)) + goto badframe; + regs->cause = -1UL; return regs->a0; @@ -323,6 +345,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct rt_sigframe __user *frame; long err = 0; unsigned long __maybe_unused addr; + unsigned long ss_ptr = 0; size_t frame_size = get_rt_frame_size(false); frame = get_sigframe(ksig, regs, frame_size); @@ -334,6 +357,23 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(NULL, &frame->uc.uc_link); + /* + * 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. + */ + if (is_shstk_enabled(current)) { + err |= save_user_shstk(current, &ss_ptr); + err |= __put_user(ss_ptr, &frame->uc.uc_mcontext.sc_cfi_state.ss_ptr); + } + err |= __save_altstack(&frame->uc.uc_stack, regs->sp); err |= setup_sigcontext(frame, regs); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); @@ -344,6 +384,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 diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c index 13920b9d86f3..db5b32500050 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) { task->thread_info.user_cfi_state.ubcfi_en = enable ? 1 : 0; @@ -168,6 +173,58 @@ 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)