From: Thomas Gleixner <tglx@linutronix.de>
To: Christophe Leroy <christophe.leroy@csgroup.eu>,
LKML <linux-kernel@vger.kernel.org>
Cc: "Linus Torvalds" <torvalds@linux-foundation.org>,
"Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
"Peter Zijlstra" <peterz@infradead.org>,
"Darren Hart" <dvhart@infradead.org>,
"Davidlohr Bueso" <dave@stgolabs.net>,
"André Almeida" <andrealmeid@igalia.com>,
x86@kernel.org, "Alexander Viro" <viro@zeniv.linux.org.uk>,
"Christian Brauner" <brauner@kernel.org>,
"Jan Kara" <jack@suse.cz>,
linux-fsdevel@vger.kernel.org
Subject: Re: [patch 1/4] uaccess: Provide common helpers for masked user access
Date: Sat, 13 Sep 2025 20:01:57 +0200 [thread overview]
Message-ID: <874it65izu.ffs@tglx> (raw)
In-Reply-To: <0424c6bc-aa12-4ee2-a062-68ce16603c26@csgroup.eu>
On Tue, Aug 26 2025 at 09:04, Christophe Leroy wrote:
> Le 13/08/2025 à 17:57, Thomas Gleixner a écrit :
>> commit 2865baf54077 ("x86: support user address masking instead of
>> non-speculative conditional") provided an optimization for
>> unsafe_get/put_user(), which optimizes the Spectre-V1 mitigation in an
>> architecture specific way. Currently only x86_64 supports that.
>>
>> The required code pattern is:
>>
>> if (can_do_masked_user_access())
>> dst = masked_user_access_begin(dst);
>> else if (!user_write_access_begin(dst, sizeof(*dst)))
>> return -EFAULT;
>> unsafe_put_user(val, dst, Efault);
>> user_read_access_end();
>
> You previously called user_write_access_begin(), so must be a
> user_write_access_end() here not a user_read_access_end().
>
>> return 0;
>> Efault:
>> user_read_access_end();
>
> Same.
>
>> return -EFAULT;
>>
>> The futex code already grew an instance of that and there are other areas,
>> which can be optimized, when the calling code actually verified before,
>> that the user pointer is both aligned and actually in user space.
>>
>> Use the futex example and provide generic helper inlines for that to avoid
>> having tons of copies all over the tree.
>>
>> This provides get/put_user_masked_uNN() where $NN is the variable size in
>> bits, i.e. 8, 16, 32, 64.
>
> Couldn't the $NN be automatically determined through the type of the
> provided user pointer (i.e. the 'from' and 'to' in patch 2) ?
>
>>
>> The second set of helpers is to encapsulate the prologue for larger access
>> patterns, e.g. multiple consecutive unsafe_put/get_user() scenarioes:
>>
>> if (can_do_masked_user_access())
>> dst = masked_user_access_begin(dst);
>> else if (!user_write_access_begin(dst, sizeof(*dst)))
>> return -EFAULT;
>> unsafe_put_user(a, &dst->a, Efault);
>> unsafe_put_user(b, &dst->b, Efault);
>> user_write_access_end();
>> return 0;
>> Efault:
>> user_write_access_end();
>> return -EFAULT;
>>
>> which allows to shorten this to:
>>
>> if (!user_write_masked_begin(dst))
>> return -EFAULT;
>> unsafe_put_user(a, &dst->a, Efault);
>> ...
>
> That's nice but ... it hides even deeper the fact that
> masked_user_access_begin() opens a read/write access to userspace. On
> x86 it doesn't matter because all userspace accesses are read/write. But
> on architectures like powerpc it becomes a problem if you do a
> read/write open then only call user_read_access_end() as write access
> might remain open.
>
> I have a patch (See [1]) that splits masked_user_access_begin() into
> three versions, one for read-only, one for write-only and one for
> read-write., so that they match user_read_access_end()
> user_write_access_end() and user_access_end() respectively.
>
> [1]
> https://patchwork.ozlabs.org/project/linuxppc-dev/patch/7b570e237f7099d564d7b1a270169428ac1f3099.1755854833.git.christophe.leroy@csgroup.eu/
>
>
>>
>> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
>> ---
>> include/linux/uaccess.h | 78 ++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 78 insertions(+)
>>
>> --- a/include/linux/uaccess.h
>> +++ b/include/linux/uaccess.h
>> @@ -569,6 +569,84 @@ static inline void user_access_restore(u
>> #define user_read_access_end user_access_end
>> #endif
>>
>> +/*
>> + * Conveniance macros to avoid spreading this pattern all over the place
>> + */
>> +#define user_read_masked_begin(src) ({ \
>> + bool __ret = true; \
>> + \
>> + if (can_do_masked_user_access()) \
>> + src = masked_user_access_begin(src); \
>
> Should call a masked_user_read_access_begin() to perform a read-only
> masked access begin, matching the read-only access begin below
>
>> + else if (!user_read_access_begin(src, sizeof(*src))) \
>> + __ret = false; \
>> + __ret; \
>> +})
>> +
>> +#define user_write_masked_begin(dst) ({ \
>> + bool __ret = true; \
>> + \
>> + if (can_do_masked_user_access()) \
>> + dst = masked_user_access_begin(dst); \
>
> Should call masked_user_write_access_begin() to perform a write-only
> masked access begin, matching the write-only access begin below
>
>> + else if (!user_write_access_begin(dst, sizeof(*dst))) \
>> + __ret = false; \
>> + __ret; \
>> +})
>
> You are missing a user_masked_begin() for read-write operations.
Duh. Let me go and rewrite this correctly. I clearly wasn't thinking straight.
>> +GEN_GET_USER_MASKED(u8)
>> +GEN_GET_USER_MASKED(u16)
>> +GEN_GET_USER_MASKED(u32)
>> +GEN_GET_USER_MASKED(u64)
>> +#undef GEN_GET_USER_MASKED
>
> Do we need four functions ? Can't we just have a get_user_masked() macro
> that relies on the type of src , just like unsafe_get_user() ?
Tried and the resulting macro maze is completely unreadable
garbage. Having a readable implementation and the four functions for the
types supported was definitely more palatable. It's not too much asked
from a developer to pick the correct one.
Thanks,
tglx
next prev parent reply other threads:[~2025-09-13 18:02 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-13 15:57 [patch 0/4] uaccess: Provide and use helpers for user masked access Thomas Gleixner
2025-08-13 15:57 ` [patch 1/4] uaccess: Provide common helpers for masked user access Thomas Gleixner
2025-08-26 7:04 ` Christophe Leroy
2025-09-13 18:01 ` Thomas Gleixner [this message]
2025-08-13 15:57 ` [patch 2/4] futex: Convert to get/put_user_masked_u32() Thomas Gleixner
2025-08-13 15:57 ` [patch 3/4] x86/futex: Use user_*_masked_begin() Thomas Gleixner
2025-08-26 7:09 ` Christophe Leroy
2025-08-13 15:57 ` [patch 4/4] select: Use user_read_masked_begin() Thomas Gleixner
2025-08-17 13:49 ` [patch 0/4] uaccess: Provide and use helpers for user masked access David Laight
2025-08-17 14:00 ` Linus Torvalds
2025-08-17 15:29 ` David Laight
2025-08-17 15:36 ` Linus Torvalds
2025-08-18 11:59 ` David Laight
2025-08-18 21:21 ` David Laight
2025-08-18 21:36 ` Linus Torvalds
2025-08-18 22:21 ` Al Viro
2025-08-18 23:00 ` Linus Torvalds
2025-08-19 0:39 ` Al Viro
2025-08-20 23:48 ` Al Viro
2025-08-21 7:45 ` Christian Brauner
2025-08-21 22:49 ` Al Viro
2025-08-19 2:39 ` Matthew Wilcox
2025-08-19 21:33 ` David Laight
2025-08-19 4:44 ` Thomas Weißschuh
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=874it65izu.ffs@tglx \
--to=tglx@linutronix.de \
--cc=andrealmeid@igalia.com \
--cc=brauner@kernel.org \
--cc=christophe.leroy@csgroup.eu \
--cc=dave@stgolabs.net \
--cc=dvhart@infradead.org \
--cc=jack@suse.cz \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=peterz@infradead.org \
--cc=torvalds@linux-foundation.org \
--cc=viro@zeniv.linux.org.uk \
--cc=x86@kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.