From nobody Sun Feb 8 11:21:23 2026 Received: from mailer.gwdg.de (mailer.gwdg.de [134.76.10.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 58AC72C0299 for ; Thu, 18 Dec 2025 19:28:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=134.76.10.26 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766086124; cv=none; b=lEd8eiibys5LEI4zvnQSwCNzMnsWcjpzuO6jPJHB1HNQzQrEwygNxk0aYb2/9ShSZvsg98Pt74OtM4j/3G6ix7qA9RceizznbsuJaZuQ10sf5UocP4OPdiBzHWk9jvCvlD0UffuanVsq77MguwxtKhQZNSprc/Fo4/2NNWNuiuo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766086124; c=relaxed/simple; bh=U+nS+AZhjSrVuKPdP5OpxOT3sYWnLmS0+zn2hlLV1v8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=UHyZu1tX9uqEACo0XyfLyHKcpWShlrVHW87Qr4oMvxG1dBYlDkftuSP2vdDkBOdC4E3semZo4Nt1HkW3QPyyPjFCsdaPq61dj+noC0jfSyByVEy4+MZlBmofaQNbPTgcXIYW9CCGl3NGuJXErMw3FJh6hGaYOsEF0zrldVROWLE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cispa.de; spf=pass smtp.mailfrom=cispa.de; arc=none smtp.client-ip=134.76.10.26 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cispa.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cispa.de Received: from mbx19-sub-05.um.gwdg.de ([10.108.142.70] helo=email.gwdg.de) by mailer.gwdg.de with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (GWDG Mailer) (envelope-from ) id 1vWJRT-000RlL-1f; Thu, 18 Dec 2025 20:13:39 +0100 Received: from localhost.localdomain (10.250.9.200) by MBX19-SUB-05.um.gwdg.de (10.108.142.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.35; Thu, 18 Dec 2025 20:13:38 +0100 From: Lukas Gerlach To: CC: , , , , , , , , , Lukas Gerlach Subject: [PATCH 1/2] riscv: Use pointer masking to limit uaccess speculation Date: Thu, 18 Dec 2025 20:13:31 +0100 Message-ID: <20251218191332.35849-2-lukas.gerlach@cispa.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251218191332.35849-1-lukas.gerlach@cispa.de> References: <20251218191332.35849-1-lukas.gerlach@cispa.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: MBX19-FMZ-05.um.gwdg.de (10.108.142.64) To MBX19-SUB-05.um.gwdg.de (10.108.142.70) X-Spam-Level: - X-Virus-Scanned: (clean) by clamav Content-Type: text/plain; charset="utf-8" Similarly to x86 and arm64, mitigate speculation past an access_ok() check by masking the pointer before use. On RISC-V, user addresses have the MSB clear while kernel addresses have the MSB set. The uaccess_mask_ptr() function clears the MSB, ensuring any kernel pointer becomes invalid and will fault, while valid user pointers remain unchanged. This prevents speculative access to kernel memory via user copy functions. The masking is applied to __get_user, __put_user, raw_copy_from_user, raw_copy_to_user, clear_user, and the unsafe_* variants. Signed-off-by: Lukas Gerlach --- arch/riscv/include/asm/uaccess.h | 41 +++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uacc= ess.h index 36bba6720c26..ceee1d62ff9b 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -74,6 +74,23 @@ static inline unsigned long __untagged_addr_remote(struc= t mm_struct *mm, unsigne #define __typefits(x, type, not) \ __builtin_choose_expr(sizeof(x) <=3D sizeof(type), (unsigned type)0, not) =20 +/* + * Sanitize a uaccess pointer such that it cannot reach any kernel address. + * + * On RISC-V, virtual addresses are sign-extended from the top implemented= bit. + * User addresses have the MSB clear; kernel addresses have the MSB set. + * Clearing the MSB ensures any kernel pointer becomes non-canonical and w= ill + * fault, while valid user pointers remain unchanged. + */ +#define uaccess_mask_ptr(ptr) ((__typeof__(ptr))__uaccess_mask_ptr(ptr)) +static inline void __user *__uaccess_mask_ptr(const void __user *ptr) +{ + unsigned long val =3D (unsigned long)ptr; + + val =3D (val << 1) >> 1; + return (void __user *)val; +} + /* * The exception table consists of pairs of addresses: the first is the * address of an instruction that is allowed to fault, and the second is @@ -235,7 +252,8 @@ __gu_failed: \ */ #define __get_user(x, ptr) \ ({ \ - const __typeof__(*(ptr)) __user *__gu_ptr =3D untagged_addr(ptr); \ + const __typeof__(*(ptr)) __user *__gu_ptr =3D \ + uaccess_mask_ptr(untagged_addr(ptr)); \ long __gu_err =3D 0; \ __typeof__(x) __gu_val; \ \ @@ -366,7 +384,8 @@ err_label: \ */ #define __put_user(x, ptr) \ ({ \ - __typeof__(*(ptr)) __user *__gu_ptr =3D untagged_addr(ptr); \ + __typeof__(*(ptr)) __user *__gu_ptr =3D \ + uaccess_mask_ptr(untagged_addr(ptr)); \ __typeof__(*__gu_ptr) __val =3D (x); \ long __pu_err =3D 0; \ \ @@ -413,13 +432,15 @@ unsigned long __must_check __asm_copy_from_user(void = *to, static inline unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n) { - return __asm_copy_from_user(to, untagged_addr(from), n); + return __asm_copy_from_user(to, + uaccess_mask_ptr(untagged_addr(from)), n); } =20 static inline unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n) { - return __asm_copy_to_user(untagged_addr(to), from, n); + return __asm_copy_to_user( + uaccess_mask_ptr(untagged_addr(to)), from, n); } =20 extern long strncpy_from_user(char *dest, const char __user *src, long cou= nt); @@ -434,7 +455,7 @@ unsigned long __must_check clear_user(void __user *to, = unsigned long n) { might_fault(); return access_ok(to, n) ? - __clear_user(untagged_addr(to), n) : n; + __clear_user(uaccess_mask_ptr(untagged_addr(to)), n) : n; } =20 #define arch_get_kernel_nofault(dst, src, type, err_label) \ @@ -461,20 +482,22 @@ static inline void user_access_restore(unsigned long = enabled) { } * the error labels - thus the macro games. */ #define arch_unsafe_put_user(x, ptr, label) \ - __put_user_nocheck(x, (ptr), label) + __put_user_nocheck(x, uaccess_mask_ptr(ptr), label) =20 #define arch_unsafe_get_user(x, ptr, label) do { \ __inttype(*(ptr)) __gu_val; \ - __get_user_nocheck(__gu_val, (ptr), label); \ + __get_user_nocheck(__gu_val, uaccess_mask_ptr(ptr), label); \ (x) =3D (__force __typeof__(*(ptr)))__gu_val; \ } while (0) =20 #define unsafe_copy_to_user(_dst, _src, _len, label) \ - if (__asm_copy_to_user_sum_enabled(_dst, _src, _len)) \ + if (__asm_copy_to_user_sum_enabled( \ + uaccess_mask_ptr(_dst), _src, _len)) \ goto label; =20 #define unsafe_copy_from_user(_dst, _src, _len, label) \ - if (__asm_copy_from_user_sum_enabled(_dst, _src, _len)) \ + if (__asm_copy_from_user_sum_enabled( \ + _dst, uaccess_mask_ptr(_src), _len)) \ goto label; =20 #else /* CONFIG_MMU */ --=20 2.51.0 From nobody Sun Feb 8 11:21:23 2026 Received: from mailer.gwdg.de (mailer.gwdg.de [134.76.10.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 48B572C0299 for ; Thu, 18 Dec 2025 19:29:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=134.76.10.26 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766086170; cv=none; b=sd8A49qpoJ6UVYisprZ8O2Xo3g9ifBRYxgmBTUKTWU/v4b+ilA+yuMIfQLnGonF0fdI63d1BaM/B/a4qwbj0g/cr4uweUmCLEPEM4fDPfYCZLJ6LWeukiaRzH6SoivJ2zjsGdXTcLVGe4tS+JQ23pd2mas7AZ2LaBKzktpyaIy4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766086170; c=relaxed/simple; bh=+dPO+pHsMQkJsBb9p68AFG+XrOl8aHsbHiCtRTtjDYE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jzaG+zCTvPhwCvM05I9+a9la/+h5vN7xWVzXveh8lHo8RXG2IwSbkN6VPA9FxH8yVHfrf313JgkBprs6VoDwauOaOqZyrRqE3N1ry7+11Dy/TFEQvqinhy1hFCooHSHbtsv/ObsjTUsyI8Uf6A19kNSw6T0hOB1bCrJdaFev0ME= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cispa.de; spf=pass smtp.mailfrom=cispa.de; arc=none smtp.client-ip=134.76.10.26 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cispa.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cispa.de Received: from mbx19-sub-05.um.gwdg.de ([10.108.142.70] helo=email.gwdg.de) by mailer.gwdg.de with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (GWDG Mailer) (envelope-from ) id 1vWJRU-000RlX-0O; Thu, 18 Dec 2025 20:13:40 +0100 Received: from localhost.localdomain (10.250.9.200) by MBX19-SUB-05.um.gwdg.de (10.108.142.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.35; Thu, 18 Dec 2025 20:13:39 +0100 From: Lukas Gerlach To: CC: , , , , , , , , , Lukas Gerlach Subject: [PATCH 2/2] riscv: Sanitize syscall table indexing under speculation Date: Thu, 18 Dec 2025 20:13:32 +0100 Message-ID: <20251218191332.35849-3-lukas.gerlach@cispa.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251218191332.35849-1-lukas.gerlach@cispa.de> References: <20251218191332.35849-1-lukas.gerlach@cispa.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: MBX19-FMZ-05.um.gwdg.de (10.108.142.64) To MBX19-SUB-05.um.gwdg.de (10.108.142.70) X-Spam-Level: - X-Virus-Scanned: (clean) by clamav Content-Type: text/plain; charset="utf-8" The syscall number is a user-controlled value used to index into the syscall table. Use array_index_nospec() to clamp this value after the bounds check to prevent speculative out-of-bounds access and subsequent data leakage via cache side channels. Signed-off-by: Lukas Gerlach --- arch/riscv/kernel/traps.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index 80230de167de..47afea4ff1a8 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -339,8 +339,10 @@ void do_trap_ecall_u(struct pt_regs *regs) =20 add_random_kstack_offset(); =20 - if (syscall >=3D 0 && syscall < NR_syscalls) + if (syscall >=3D 0 && syscall < NR_syscalls) { + syscall =3D array_index_nospec(syscall, NR_syscalls); syscall_handler(regs, syscall); + } =20 /* * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(), --=20 2.51.0