[PATCH 1/2] riscv: Use pointer masking to limit uaccess speculation
David Laight
david.laight.linux at gmail.com
Mon Dec 29 04:32:12 PST 2025
On Sun, 28 Dec 2025 22:34:30 +0000
David Laight <david.laight.linux at gmail.com> wrote:
> On Sat, 27 Dec 2025 17:59:38 -0800
> Deepak Gupta <debug at rivosinc.com> wrote:
>
> > On Sat, Dec 27, 2025 at 09:28:59PM +0000, David Laight wrote:
> > >On Fri, 19 Dec 2025 16:44:11 -0800
> > >Deepak Gupta <debug at rivosinc.com> wrote:
> > >
> > >> On Thu, Dec 18, 2025 at 08:13:31PM +0100, Lukas Gerlach wrote:
> > >> >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 <lukas.gerlach at cispa.de>
> > >> >---
> > >> > 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/uaccess.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(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.
> > >> >+ *
> > >> >+ * 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 will
> > >> >+ * 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 = (unsigned long)ptr;
> > >> >+
> > >> >+ val = (val << 1) >> 1;
> > >> >+ return (void __user *)val;
> > >>
> > >> This is only clearing b63 which is what we don't need here.
> > >
> > >It is also entirely the wrong operation.
> > >A kernel address needs converting into an address that is guaranteed
> > >to fault - not a user address that might be valid.
> >
> > This is about speculative accesses and not actual accesses. Due to some
> > speculation it is possible that in speculative path a wrong address is
> > generated with MSB=1. This simply ensures that bit is cleared for agen
> > even in speculative path.
>
> You said you were following what x86 did - this isn't what is does.
> Avoiding the conditional branch in access_ok() is actually a big win.
> That is true even without the issues with speculative accesses to kernel
> memory.
> The 'address masking' (badly named - it isn't just masking) is a replacement
> for access_ok(), it changes kernel addresses to invalid ones so that the
> access faults and the trap/fault fixup code detects the error.
If you can guarantee that address 0 is never mapped into userspace
(not true for x86 for historic reasons) then I think you can convert
kernel addresses to zero - which will then fault.
This is simpler than using the base of the guard page (which is still
needed for sequential accesses).
Something like:
addr &= (addr >= guard_page) - 1;
will then work - but it needs (partially) coding in assembler to
guarantee that 'setae' (or equivalent) is used rather than a
conditional branch.
David
More information about the linux-riscv
mailing list