[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20251229123212.25ef3c4b@pumpkin>
Date: Mon, 29 Dec 2025 12:32:12 +0000
From: David Laight <david.laight.linux@...il.com>
To: Deepak Gupta <debug@...osinc.com>
Cc: Lukas Gerlach <lukas.gerlach@...pa.de>, linux-riscv@...ts.infradead.org,
palmer@...belt.com, pjw@...nel.org, aou@...s.berkeley.edu, alex@...ti.fr,
linux-kernel@...r.kernel.org, daniel.weber@...pa.de,
michael.schwarz@...pa.de, marton.bognar@...euven.be,
jo.vanbulck@...euven.be
Subject: Re: [PATCH 1/2] riscv: Use pointer masking to limit uaccess
speculation
On Sun, 28 Dec 2025 22:34:30 +0000
David Laight <david.laight.linux@...il.com> wrote:
> On Sat, 27 Dec 2025 17:59:38 -0800
> Deepak Gupta <debug@...osinc.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@...osinc.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@...pa.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
Powered by blists - more mailing lists