From: Lukas Gerlach <lukas.gerlach@cispa.de>
To: Paul Walmsley <pjw@kernel.org>,
Palmer Dabbelt <palmer@dabbelt.com>,
Albert Ou <aou@eecs.berkeley.edu>,
Alexandre Ghiti <alex@ghiti.fr>
Cc: <linux-riscv@lists.infradead.org>, <linux-kernel@vger.kernel.org>,
David Laight <david.laight.linux@gmail.com>,
Deepak Gupta <debug@rivosinc.com>,
Vivian Wang <wangruikang@iscas.ac.cn>,
Daniel Weber <daniel.weber@cispa.de>,
Michael Schwarz <michael.schwarz@cispa.de>,
Marton Bognar <marton.bognar@kuleuven.be>,
Jo Van Bulck <jo.vanbulck@kuleuven.be>,
Lukas Gerlach <lukas.gerlach@cispa.de>
Subject: [PATCH v2] riscv: Limit uaccess speculation using guard page
Date: Thu, 26 Feb 2026 16:03:46 +0100 [thread overview]
Message-ID: <20260226-uaccess-guard-v2-v2-1-765a314839bc@cispa.de> (raw)
User pointers passed to uaccess routines can be speculatively used
before access_ok() validates them, potentially leaking kernel memory.
Clamp any address >= TASK_SIZE to the guard page at TASK_SIZE-1, which
will always fault. The clamp is branchless to prevent speculative bypass.
Unlike the v1 approach of clearing the sign bit, this works with all
paging modes (Sv39/Sv48/Sv57) and does not interfere with the pointer
masking extension (Smnpm).
Similar to commit 4d8efc2d5ee4 ("arm64: Use pointer masking to limit
uaccess speculation").
Signed-off-by: Lukas Gerlach <lukas.gerlach@cispa.de>
---
arch/riscv/include/asm/uaccess.h | 38 +++++++++++++++++++++++++++++---------
1 file changed, 29 insertions(+), 9 deletions(-)
diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h
index 11c9886c3b70..df31df3bd55c 100644
--- a/arch/riscv/include/asm/uaccess.h
+++ b/arch/riscv/include/asm/uaccess.h
@@ -74,6 +74,20 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigne
#define __typefits(x, type, not) \
__builtin_choose_expr(sizeof(x) <= sizeof(type), (unsigned type)0, not)
+/*
+ * Sanitize a uaccess pointer such that it cannot reach any kernel address.
+ * Branchlessly clamp any address >= TASK_SIZE to the unmapped guard page
+ * at TASK_SIZE-1, which will always fault on access.
+ */
+#define uaccess_mask_ptr(ptr) ((__typeof__(ptr))__uaccess_mask_ptr(ptr))
+static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
+{
+ unsigned long p = (unsigned long)ptr;
+ unsigned long mask = (unsigned long)((long)(TASK_SIZE - 1 - p) >> 63);
+
+ return (void __user *)((p & ~mask) | ((TASK_SIZE - 1) & mask));
+}
+
/*
* 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
@@ -245,7 +259,8 @@ __gu_failed: \
*/
#define __get_user(x, ptr) \
({ \
- const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
+ const __typeof__(*(ptr)) __user *__gu_ptr = \
+ uaccess_mask_ptr(untagged_addr(ptr)); \
long __gu_err = 0; \
__typeof__(x) __gu_val; \
\
@@ -376,7 +391,8 @@ err_label: \
*/
#define __put_user(x, ptr) \
({ \
- __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
+ __typeof__(*(ptr)) __user *__gu_ptr = \
+ uaccess_mask_ptr(untagged_addr(ptr)); \
__typeof__(*__gu_ptr) __val = (x); \
long __pu_err = 0; \
\
@@ -423,13 +439,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);
}
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);
}
extern long strncpy_from_user(char *dest, const char __user *src, long count);
@@ -444,7 +462,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;
}
#define arch_get_kernel_nofault(dst, src, type, err_label) \
@@ -471,20 +489,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)
#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) = (__force __typeof__(*(ptr)))__gu_val; \
} while (0)
#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;
#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;
#else /* CONFIG_MMU */
---
base-commit: f4d0ec0aa20d49f09dc01d82894ce80d72de0560
change-id: 20260226-uaccess-guard-v2-7a3358bee742
Best regards,
--
Lukas Gerlach <lukas.gerlach@cispa.de>
next reply other threads:[~2026-02-26 15:03 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-26 15:03 Lukas Gerlach [this message]
2026-03-04 15:57 ` kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260226-uaccess-guard-v2-v2-1-765a314839bc@cispa.de \
--to=lukas.gerlach@cispa.de \
--cc=alex@ghiti.fr \
--cc=aou@eecs.berkeley.edu \
--cc=daniel.weber@cispa.de \
--cc=david.laight.linux@gmail.com \
--cc=debug@rivosinc.com \
--cc=jo.vanbulck@kuleuven.be \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=marton.bognar@kuleuven.be \
--cc=michael.schwarz@cispa.de \
--cc=palmer@dabbelt.com \
--cc=pjw@kernel.org \
--cc=wangruikang@iscas.ac.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®