* [PATCH v4 01/10] iter: Avoid barrier_nospec() in copy_from_user_iter()
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 02/10] uaccess: Add speculation barrier to copy_from_user_iter() Christophe Leroy
` (9 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
Following patch will add missing barrier_nospec() to
copy_from_user_iter().
Avoid it for architectures supporting masked user
accesses, the same way as done for copy_from_user() by
commit 0fc810ae3ae1 ("x86/uaccess: Avoid barrier_nospec()
in 64-bit copy_from_user()")
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v2: New in v2
---
lib/iov_iter.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 2fe66a6b8789e..a589935bf3025 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -49,12 +49,16 @@ size_t copy_from_user_iter(void __user *iter_from, size_t progress,
if (should_fail_usercopy())
return len;
- if (access_ok(iter_from, len)) {
- to += progress;
- instrument_copy_from_user_before(to, iter_from, len);
- res = raw_copy_from_user(to, iter_from, len);
- instrument_copy_from_user_after(to, iter_from, len, res);
- }
+ if (can_do_masked_user_access())
+ iter_from = mask_user_address(iter_from);
+ else if (!access_ok(iter_from, len))
+ return res;
+
+ to += progress;
+ instrument_copy_from_user_before(to, iter_from, len);
+ res = raw_copy_from_user(to, iter_from, len);
+ instrument_copy_from_user_after(to, iter_from, len, res);
+
return res;
}
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH v4 02/10] uaccess: Add speculation barrier to copy_from_user_iter()
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 01/10] iter: Avoid barrier_nospec() in copy_from_user_iter() Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-15 15:51 ` Thomas Gleixner
2025-11-06 11:31 ` [PATCH v4 03/10] uaccess: Use masked_user_{read/write}_access_begin when required Christophe Leroy
` (8 subsequent siblings)
10 siblings, 1 reply; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
The results of "access_ok()" can be mis-speculated. The result is that
you can end speculatively:
if (access_ok(from, size))
// Right here
For the same reason as done in copy_from_user() by
commit 74e19ef0ff80 ("uaccess: Add speculation barrier to
copy_from_user()"), add a speculation barrier to copy_from_user_iter().
See commit 74e19ef0ff80 ("uaccess: Add speculation barrier to
copy_from_user()") for more details.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
lib/iov_iter.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index a589935bf3025..896760bad455f 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -49,11 +49,19 @@ size_t copy_from_user_iter(void __user *iter_from, size_t progress,
if (should_fail_usercopy())
return len;
- if (can_do_masked_user_access())
+ if (can_do_masked_user_access()) {
iter_from = mask_user_address(iter_from);
- else if (!access_ok(iter_from, len))
- return res;
+ } else {
+ if (!access_ok(iter_from, len))
+ return res;
+ /*
+ * Ensure that bad access_ok() speculation will not
+ * lead to nasty side effects *after* the copy is
+ * finished:
+ */
+ barrier_nospec();
+ }
to += progress;
instrument_copy_from_user_before(to, iter_from, len);
res = raw_copy_from_user(to, iter_from, len);
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v4 02/10] uaccess: Add speculation barrier to copy_from_user_iter()
2025-11-06 11:31 ` [PATCH v4 02/10] uaccess: Add speculation barrier to copy_from_user_iter() Christophe Leroy
@ 2025-11-15 15:51 ` Thomas Gleixner
2025-11-17 7:06 ` Christophe Leroy (CS GROUP)
0 siblings, 1 reply; 18+ messages in thread
From: Thomas Gleixner @ 2025-11-15 15:51 UTC (permalink / raw)
To: Christophe Leroy, Alexander Viro, Christian Brauner, Jan Kara,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
On Thu, Nov 06 2025 at 12:31, Christophe Leroy wrote:
> The results of "access_ok()" can be mis-speculated. The result is that
> you can end speculatively:
>
> if (access_ok(from, size))
> // Right here
This is actually the wrong patch ordering as the barrier is missing in
the current code. So please add the missing barrier first.
As a bonus the subject of the first patch makes actually sense
then. Right now it does not because there is nothing to avoid :)
Also please use the same prefix for these two patches which touch the
iter code.
> For the same reason as done in copy_from_user() by
> commit 74e19ef0ff80 ("uaccess: Add speculation barrier to
> copy_from_user()"), add a speculation barrier to copy_from_user_iter().
>
> See commit 74e19ef0ff80 ("uaccess: Add speculation barrier to
> copy_from_user()") for more details.
No need to repeat that. Anyone with more than two braincells can look at
that commit, which you mentioned already two lines above already.
Thanks,
tglx
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v4 02/10] uaccess: Add speculation barrier to copy_from_user_iter()
2025-11-15 15:51 ` Thomas Gleixner
@ 2025-11-17 7:06 ` Christophe Leroy (CS GROUP)
0 siblings, 0 replies; 18+ messages in thread
From: Christophe Leroy (CS GROUP) @ 2025-11-17 7:06 UTC (permalink / raw)
To: Thomas Gleixner, Alexander Viro, Christian Brauner, Jan Kara,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: linux-block, linux-fsdevel, linux-kernel, netdev, linuxppc-dev
Le 15/11/2025 à 16:51, Thomas Gleixner a écrit :
> On Thu, Nov 06 2025 at 12:31, Christophe Leroy wrote:
>> The results of "access_ok()" can be mis-speculated. The result is that
>> you can end speculatively:
>>
>> if (access_ok(from, size))
>> // Right here
>
> This is actually the wrong patch ordering as the barrier is missing in
> the current code. So please add the missing barrier first.
Patch 1 is there because Linus was worried with the performance
degradation brought by the barrier on x86, see [1]
[1]
https://lore.kernel.org/all/CAHk-=wj4P6p1kBVW7aJbWAOGJZkB7fXFmwaXLieBRhjmvnWgvQ@mail.gmail.com/
If we change the order, it means we first degrade performance on x86
with patch 1 then we fix that degradation with patch 2. It seems more
natural to first ensure that the barrier won't degrade x86 then add the
barrier.
An alternative is to squash both patches together, after all they touch
the exact same part of the code.
Let me know what you prefer:
1/ Leave in that order to avoid intermediaite performance degradation on x86
2/ Change order
3/ Squash both patches together.
>
> As a bonus the subject of the first patch makes actually sense
> then. Right now it does not because there is nothing to avoid :)
>
> Also please use the same prefix for these two patches which touch the
> iter code.
Sure I'll do that.
>
>> For the same reason as done in copy_from_user() by
>> commit 74e19ef0ff80 ("uaccess: Add speculation barrier to
>> copy_from_user()"), add a speculation barrier to copy_from_user_iter().
>>
>> See commit 74e19ef0ff80 ("uaccess: Add speculation barrier to
>> copy_from_user()") for more details.
>
> No need to repeat that. Anyone with more than two braincells can look at
> that commit, which you mentioned already two lines above already.
Ok
Thanks
Christophe
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 03/10] uaccess: Use masked_user_{read/write}_access_begin when required
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 01/10] iter: Avoid barrier_nospec() in copy_from_user_iter() Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 02/10] uaccess: Add speculation barrier to copy_from_user_iter() Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-15 15:53 ` Thomas Gleixner
2025-11-06 11:31 ` [PATCH v4 04/10] powerpc/uaccess: Move barrier_nospec() out of allow_read_{from/write}_user() Christophe Leroy
` (7 subsequent siblings)
10 siblings, 1 reply; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
Properly use masked_user_read_access_begin() and
masked_user_write_access_begin() instead of masked_user_access_begin()
in order to match user_read_access_end() and user_write_access_end().
This is important for architectures like powerpc that enable
separately user reads and user writes.
That means masked_user_read_access_begin() is used when user memory is
exclusively read during the window and masked_user_write_access_begin()
is used when user memory is exclusively writen during the window.
masked_user_access_begin() remains and is used when both reads and
writes are performed during the open window. Each of them is expected
to be terminated by the matching user_read_access_end(),
user_write_access_end() and user_access_end().
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v4: Rebased on top of core-scoped-uaccess tag
v3: Rebased on top of v6.18-rc1 ==> change in net/core/scm.c
v2: Added more explanations in the commit message following comments received.
---
lib/strncpy_from_user.c | 2 +-
lib/strnlen_user.c | 2 +-
net/core/scm.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c
index 6dc234913dd58..5bb752ff7c61b 100644
--- a/lib/strncpy_from_user.c
+++ b/lib/strncpy_from_user.c
@@ -126,7 +126,7 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
if (can_do_masked_user_access()) {
long retval;
- src = masked_user_access_begin(src);
+ src = masked_user_read_access_begin(src);
retval = do_strncpy_from_user(dst, src, count, count);
user_read_access_end();
return retval;
diff --git a/lib/strnlen_user.c b/lib/strnlen_user.c
index 6e489f9e90f15..4a6574b67f824 100644
--- a/lib/strnlen_user.c
+++ b/lib/strnlen_user.c
@@ -99,7 +99,7 @@ long strnlen_user(const char __user *str, long count)
if (can_do_masked_user_access()) {
long retval;
- str = masked_user_access_begin(str);
+ str = masked_user_read_access_begin(str);
retval = do_strnlen_user(str, count, count);
user_read_access_end();
return retval;
diff --git a/net/core/scm.c b/net/core/scm.c
index 66eaee783e8be..4a65f9baa87e7 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -274,7 +274,7 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
check_object_size(data, cmlen - sizeof(*cm), true);
if (can_do_masked_user_access())
- cm = masked_user_access_begin(cm);
+ cm = masked_user_write_access_begin(cm);
else if (!user_write_access_begin(cm, cmlen))
goto efault;
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v4 03/10] uaccess: Use masked_user_{read/write}_access_begin when required
2025-11-06 11:31 ` [PATCH v4 03/10] uaccess: Use masked_user_{read/write}_access_begin when required Christophe Leroy
@ 2025-11-15 15:53 ` Thomas Gleixner
2025-11-17 7:11 ` Christophe Leroy (CS GROUP)
0 siblings, 1 reply; 18+ messages in thread
From: Thomas Gleixner @ 2025-11-15 15:53 UTC (permalink / raw)
To: Christophe Leroy, Alexander Viro, Christian Brauner, Jan Kara,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
On Thu, Nov 06 2025 at 12:31, Christophe Leroy wrote:
> diff --git a/net/core/scm.c b/net/core/scm.c
> index 66eaee783e8be..4a65f9baa87e7 100644
> --- a/net/core/scm.c
> +++ b/net/core/scm.c
> @@ -274,7 +274,7 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
> check_object_size(data, cmlen - sizeof(*cm), true);
>
> if (can_do_masked_user_access())
> - cm = masked_user_access_begin(cm);
> + cm = masked_user_write_access_begin(cm);
> else if (!user_write_access_begin(cm, cmlen))
> goto efault;
Shouldn't this be converted to scoped_....() ?
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v4 03/10] uaccess: Use masked_user_{read/write}_access_begin when required
2025-11-15 15:53 ` Thomas Gleixner
@ 2025-11-17 7:11 ` Christophe Leroy (CS GROUP)
0 siblings, 0 replies; 18+ messages in thread
From: Christophe Leroy (CS GROUP) @ 2025-11-17 7:11 UTC (permalink / raw)
To: Thomas Gleixner, Alexander Viro, Christian Brauner, Jan Kara,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: linux-block, linux-fsdevel, linux-kernel, netdev, linuxppc-dev
Le 15/11/2025 à 16:53, Thomas Gleixner a écrit :
> On Thu, Nov 06 2025 at 12:31, Christophe Leroy wrote:
>> diff --git a/net/core/scm.c b/net/core/scm.c
>> index 66eaee783e8be..4a65f9baa87e7 100644
>> --- a/net/core/scm.c
>> +++ b/net/core/scm.c
>> @@ -274,7 +274,7 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
>> check_object_size(data, cmlen - sizeof(*cm), true);
>>
>> if (can_do_masked_user_access())
>> - cm = masked_user_access_begin(cm);
>> + cm = masked_user_write_access_begin(cm);
>> else if (!user_write_access_begin(cm, cmlen))
>> goto efault;
>
> Shouldn't this be converted to scoped_....() ?
Sure. I made the same comment to you when reviewing your series, see [1]
[1]
https://lore.kernel.org/all/e0795f90-1030-4954-aefc-be137e9db49e@csgroup.eu/
Do you prefer me to do it as part of my series ?
Christophe
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 04/10] powerpc/uaccess: Move barrier_nospec() out of allow_read_{from/write}_user()
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
` (2 preceding siblings ...)
2025-11-06 11:31 ` [PATCH v4 03/10] uaccess: Use masked_user_{read/write}_access_begin when required Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 05/10] powerpc/uaccess: Remove unused size and from parameters from allow_access_user() Christophe Leroy
` (6 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
Commit 74e19ef0ff80 ("uaccess: Add speculation barrier to
copy_from_user()") added a redundant barrier_nospec() in
copy_from_user(), because powerpc is already calling
barrier_nospec() in allow_read_from_user() and
allow_read_write_user(). But on other architectures that
call to barrier_nospec() was missing. So change powerpc
instead of reverting the above commit and having to fix
other architectures one by one. This is now possible
because barrier_nospec() has also been added in
copy_from_user_iter().
Move barrier_nospec() out of allow_read_from_user() and
allow_read_write_user(). This will also allow reuse of those
functions when implementing masked user access which doesn't
require barrier_nospec().
Don't add it back in raw_copy_from_user() as it is already called
by copy_from_user() and copy_from_user_iter().
Fixes: 74e19ef0ff80 ("uaccess: Add speculation barrier to copy_from_user()")
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/include/asm/kup.h | 2 --
arch/powerpc/include/asm/uaccess.h | 4 ++++
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index dab63b82a8d4f..f2009d7c8cfa7 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -134,7 +134,6 @@ static __always_inline void kuap_assert_locked(void)
static __always_inline void allow_read_from_user(const void __user *from, unsigned long size)
{
- barrier_nospec();
allow_user_access(NULL, from, size, KUAP_READ);
}
@@ -146,7 +145,6 @@ static __always_inline void allow_write_to_user(void __user *to, unsigned long s
static __always_inline void allow_read_write_user(void __user *to, const void __user *from,
unsigned long size)
{
- barrier_nospec();
allow_user_access(to, from, size, KUAP_READ_WRITE);
}
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index 784a00e681fa3..3e622e647d622 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -301,6 +301,7 @@ do { \
__typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr)); \
\
might_fault(); \
+ barrier_nospec(); \
allow_read_from_user(__gu_addr, __gu_size); \
__get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \
prevent_read_from_user(__gu_addr, __gu_size); \
@@ -329,6 +330,7 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
{
unsigned long ret;
+ barrier_nospec();
allow_read_write_user(to, from, n);
ret = __copy_tofrom_user(to, from, n);
prevent_read_write_user(to, from, n);
@@ -415,6 +417,7 @@ static __must_check __always_inline bool user_access_begin(const void __user *pt
might_fault();
+ barrier_nospec();
allow_read_write_user((void __user *)ptr, ptr, len);
return true;
}
@@ -431,6 +434,7 @@ user_read_access_begin(const void __user *ptr, size_t len)
might_fault();
+ barrier_nospec();
allow_read_from_user(ptr, len);
return true;
}
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH v4 05/10] powerpc/uaccess: Remove unused size and from parameters from allow_access_user()
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
` (3 preceding siblings ...)
2025-11-06 11:31 ` [PATCH v4 04/10] powerpc/uaccess: Move barrier_nospec() out of allow_read_{from/write}_user() Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 06/10] powerpc/uaccess: Remove {allow/prevent}_{read/write/read_write}_{from/to/}_user() Christophe Leroy
` (5 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
Since commit 16132529cee5 ("powerpc/32s: Rework Kernel Userspace
Access Protection") the size parameter is unused on all platforms.
And the 'from' parameter has never been used.
Remove them.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v2: Also remove 'from' param.
---
arch/powerpc/include/asm/book3s/32/kup.h | 3 +--
arch/powerpc/include/asm/book3s/64/kup.h | 6 ++----
arch/powerpc/include/asm/kup.h | 9 ++++-----
arch/powerpc/include/asm/nohash/32/kup-8xx.h | 3 +--
arch/powerpc/include/asm/nohash/kup-booke.h | 3 +--
5 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/32/kup.h b/arch/powerpc/include/asm/book3s/32/kup.h
index 873c5146e3261..a3558419c41b1 100644
--- a/arch/powerpc/include/asm/book3s/32/kup.h
+++ b/arch/powerpc/include/asm/book3s/32/kup.h
@@ -97,8 +97,7 @@ static __always_inline unsigned long __kuap_get_and_assert_locked(void)
}
#define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
-static __always_inline void allow_user_access(void __user *to, const void __user *from,
- u32 size, unsigned long dir)
+static __always_inline void allow_user_access(void __user *to, unsigned long dir)
{
BUILD_BUG_ON(!__builtin_constant_p(dir));
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h b/arch/powerpc/include/asm/book3s/64/kup.h
index 03aec3c6c851c..9ccf8a5e0926f 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -353,8 +353,7 @@ __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
return (regs->amr & AMR_KUAP_BLOCK_READ) == AMR_KUAP_BLOCK_READ;
}
-static __always_inline void allow_user_access(void __user *to, const void __user *from,
- unsigned long size, unsigned long dir)
+static __always_inline void allow_user_access(void __user *to, unsigned long dir)
{
unsigned long thread_amr = 0;
@@ -383,8 +382,7 @@ static __always_inline unsigned long get_kuap(void)
static __always_inline void set_kuap(unsigned long value) { }
-static __always_inline void allow_user_access(void __user *to, const void __user *from,
- unsigned long size, unsigned long dir)
+static __always_inline void allow_user_access(void __user *to, unsigned long dir)
{ }
#endif /* !CONFIG_PPC_KUAP */
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index f2009d7c8cfa7..3963584ac1cf1 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -72,8 +72,7 @@ static __always_inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned
* platforms.
*/
#ifndef CONFIG_PPC_BOOK3S_64
-static __always_inline void allow_user_access(void __user *to, const void __user *from,
- unsigned long size, unsigned long dir) { }
+static __always_inline void allow_user_access(void __user *to, unsigned long dir) { }
static __always_inline void prevent_user_access(unsigned long dir) { }
static __always_inline unsigned long prevent_user_access_return(void) { return 0UL; }
static __always_inline void restore_user_access(unsigned long flags) { }
@@ -134,18 +133,18 @@ static __always_inline void kuap_assert_locked(void)
static __always_inline void allow_read_from_user(const void __user *from, unsigned long size)
{
- allow_user_access(NULL, from, size, KUAP_READ);
+ allow_user_access(NULL, KUAP_READ);
}
static __always_inline void allow_write_to_user(void __user *to, unsigned long size)
{
- allow_user_access(to, NULL, size, KUAP_WRITE);
+ allow_user_access(to, KUAP_WRITE);
}
static __always_inline void allow_read_write_user(void __user *to, const void __user *from,
unsigned long size)
{
- allow_user_access(to, from, size, KUAP_READ_WRITE);
+ allow_user_access(to, KUAP_READ_WRITE);
}
static __always_inline void prevent_read_from_user(const void __user *from, unsigned long size)
diff --git a/arch/powerpc/include/asm/nohash/32/kup-8xx.h b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
index 08486b15b2075..efffb5006d190 100644
--- a/arch/powerpc/include/asm/nohash/32/kup-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
@@ -49,8 +49,7 @@ static __always_inline void uaccess_end_8xx(void)
"i"(SPRN_MD_AP), "r"(MD_APG_KUAP), "i"(MMU_FTR_KUAP) : "memory");
}
-static __always_inline void allow_user_access(void __user *to, const void __user *from,
- unsigned long size, unsigned long dir)
+static __always_inline void allow_user_access(void __user *to, unsigned long dir)
{
uaccess_begin_8xx(MD_APG_INIT);
}
diff --git a/arch/powerpc/include/asm/nohash/kup-booke.h b/arch/powerpc/include/asm/nohash/kup-booke.h
index d6bbb6d78bbe4..cb2d5a96c3df7 100644
--- a/arch/powerpc/include/asm/nohash/kup-booke.h
+++ b/arch/powerpc/include/asm/nohash/kup-booke.h
@@ -73,8 +73,7 @@ static __always_inline void uaccess_end_booke(void)
"i"(SPRN_PID), "r"(0), "i"(MMU_FTR_KUAP) : "memory");
}
-static __always_inline void allow_user_access(void __user *to, const void __user *from,
- unsigned long size, unsigned long dir)
+static __always_inline void allow_user_access(void __user *to, unsigned long dir)
{
uaccess_begin_booke(current->thread.pid);
}
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH v4 06/10] powerpc/uaccess: Remove {allow/prevent}_{read/write/read_write}_{from/to/}_user()
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
` (4 preceding siblings ...)
2025-11-06 11:31 ` [PATCH v4 05/10] powerpc/uaccess: Remove unused size and from parameters from allow_access_user() Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 07/10] powerpc/uaccess: Refactor user_{read/write/}_access_begin() Christophe Leroy
` (4 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
The six following functions have become simple single-line fonctions
that do not have much added value anymore:
- allow_read_from_user()
- allow_write_to_user()
- allow_read_write_user()
- prevent_read_from_user()
- prevent_write_to_user()
- prevent_read_write_user()
Directly call allow_user_access() and prevent_user_access(), it doesn't
reduce the readability and it removes unnecessary middle functions.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v2: New
---
arch/powerpc/include/asm/kup.h | 47 ------------------------------
arch/powerpc/include/asm/uaccess.h | 30 +++++++++----------
2 files changed, 15 insertions(+), 62 deletions(-)
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 3963584ac1cf1..4a4145a244f29 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -131,53 +131,6 @@ static __always_inline void kuap_assert_locked(void)
kuap_get_and_assert_locked();
}
-static __always_inline void allow_read_from_user(const void __user *from, unsigned long size)
-{
- allow_user_access(NULL, KUAP_READ);
-}
-
-static __always_inline void allow_write_to_user(void __user *to, unsigned long size)
-{
- allow_user_access(to, KUAP_WRITE);
-}
-
-static __always_inline void allow_read_write_user(void __user *to, const void __user *from,
- unsigned long size)
-{
- allow_user_access(to, KUAP_READ_WRITE);
-}
-
-static __always_inline void prevent_read_from_user(const void __user *from, unsigned long size)
-{
- prevent_user_access(KUAP_READ);
-}
-
-static __always_inline void prevent_write_to_user(void __user *to, unsigned long size)
-{
- prevent_user_access(KUAP_WRITE);
-}
-
-static __always_inline void prevent_read_write_user(void __user *to, const void __user *from,
- unsigned long size)
-{
- prevent_user_access(KUAP_READ_WRITE);
-}
-
-static __always_inline void prevent_current_access_user(void)
-{
- prevent_user_access(KUAP_READ_WRITE);
-}
-
-static __always_inline void prevent_current_read_from_user(void)
-{
- prevent_user_access(KUAP_READ);
-}
-
-static __always_inline void prevent_current_write_to_user(void)
-{
- prevent_user_access(KUAP_WRITE);
-}
-
#endif /* !__ASSEMBLER__ */
#endif /* _ASM_POWERPC_KUAP_H_ */
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index 3e622e647d622..7846ee59e3747 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -45,14 +45,14 @@
do { \
__label__ __pu_failed; \
\
- allow_write_to_user(__pu_addr, __pu_size); \
+ allow_user_access(__pu_addr, KUAP_WRITE); \
__put_user_size_goto(__pu_val, __pu_addr, __pu_size, __pu_failed); \
- prevent_write_to_user(__pu_addr, __pu_size); \
+ prevent_user_access(KUAP_WRITE); \
__pu_err = 0; \
break; \
\
__pu_failed: \
- prevent_write_to_user(__pu_addr, __pu_size); \
+ prevent_user_access(KUAP_WRITE); \
__pu_err = -EFAULT; \
} while (0); \
\
@@ -302,9 +302,9 @@ do { \
\
might_fault(); \
barrier_nospec(); \
- allow_read_from_user(__gu_addr, __gu_size); \
+ allow_user_access(NULL, KUAP_READ); \
__get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \
- prevent_read_from_user(__gu_addr, __gu_size); \
+ prevent_user_access(KUAP_READ); \
(x) = (__typeof__(*(ptr)))__gu_val; \
\
__gu_err; \
@@ -331,9 +331,9 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
unsigned long ret;
barrier_nospec();
- allow_read_write_user(to, from, n);
+ allow_user_access(to, KUAP_READ_WRITE);
ret = __copy_tofrom_user(to, from, n);
- prevent_read_write_user(to, from, n);
+ prevent_user_access(KUAP_READ_WRITE);
return ret;
}
#endif /* __powerpc64__ */
@@ -343,9 +343,9 @@ static inline unsigned long raw_copy_from_user(void *to,
{
unsigned long ret;
- allow_read_from_user(from, n);
+ allow_user_access(NULL, KUAP_READ);
ret = __copy_tofrom_user((__force void __user *)to, from, n);
- prevent_read_from_user(from, n);
+ prevent_user_access(KUAP_READ);
return ret;
}
@@ -354,9 +354,9 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
{
unsigned long ret;
- allow_write_to_user(to, n);
+ allow_user_access(to, KUAP_WRITE);
ret = __copy_tofrom_user(to, (__force const void __user *)from, n);
- prevent_write_to_user(to, n);
+ prevent_user_access(KUAP_WRITE);
return ret;
}
@@ -367,9 +367,9 @@ static inline unsigned long __clear_user(void __user *addr, unsigned long size)
unsigned long ret;
might_fault();
- allow_write_to_user(addr, size);
+ allow_user_access(addr, KUAP_WRITE);
ret = __arch_clear_user(addr, size);
- prevent_write_to_user(addr, size);
+ prevent_user_access(KUAP_WRITE);
return ret;
}
@@ -397,9 +397,9 @@ copy_mc_to_user(void __user *to, const void *from, unsigned long n)
{
if (check_copy_size(from, n, true)) {
if (access_ok(to, n)) {
- allow_write_to_user(to, n);
+ allow_user_access(to, KUAP_WRITE);
n = copy_mc_generic((void __force *)to, from, n);
- prevent_write_to_user(to, n);
+ prevent_user_access(KUAP_WRITE);
}
}
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH v4 07/10] powerpc/uaccess: Refactor user_{read/write/}_access_begin()
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
` (5 preceding siblings ...)
2025-11-06 11:31 ` [PATCH v4 06/10] powerpc/uaccess: Remove {allow/prevent}_{read/write/read_write}_{from/to/}_user() Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 08/10] powerpc/32s: Fix segments setup when TASK_SIZE is not a multiple of 256M Christophe Leroy
` (3 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
user_read_access_begin() and user_write_access_begin() and
user_access_begin() are now very similar. Create a common
__user_access_begin() that takes direction as parameter.
In order to avoid a warning with the conditional call of
barrier_nospec() which is sometimes an empty macro, change it to a
do {} while (0).
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v4: Rebase on top of core-scoped-uaccess tag
v2: New
---
arch/powerpc/include/asm/barrier.h | 2 +-
arch/powerpc/include/asm/uaccess.h | 46 +++++++++---------------------
2 files changed, 14 insertions(+), 34 deletions(-)
diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h
index 9e9833faa4af8..9d2f612cfb1d7 100644
--- a/arch/powerpc/include/asm/barrier.h
+++ b/arch/powerpc/include/asm/barrier.h
@@ -102,7 +102,7 @@ do { \
#else /* !CONFIG_PPC_BARRIER_NOSPEC */
#define barrier_nospec_asm
-#define barrier_nospec()
+#define barrier_nospec() do {} while (0)
#endif /* CONFIG_PPC_BARRIER_NOSPEC */
/*
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index 7846ee59e3747..721d65dbbb2e5 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -410,50 +410,30 @@ copy_mc_to_user(void __user *to, const void *from, unsigned long n)
extern long __copy_from_user_flushcache(void *dst, const void __user *src,
unsigned size);
-static __must_check __always_inline bool user_access_begin(const void __user *ptr, size_t len)
+static __must_check __always_inline bool __user_access_begin(const void __user *ptr, size_t len,
+ unsigned long dir)
{
if (unlikely(!access_ok(ptr, len)))
return false;
might_fault();
- barrier_nospec();
- allow_read_write_user((void __user *)ptr, ptr, len);
+ if (dir & KUAP_READ)
+ barrier_nospec();
+ allow_user_access((void __user *)ptr, dir);
return true;
}
-#define user_access_begin user_access_begin
-#define user_access_end prevent_current_access_user
-#define user_access_save prevent_user_access_return
-#define user_access_restore restore_user_access
-static __must_check __always_inline bool
-user_read_access_begin(const void __user *ptr, size_t len)
-{
- if (unlikely(!access_ok(ptr, len)))
- return false;
+#define user_access_begin(p, l) __user_access_begin(p, l, KUAP_READ_WRITE)
+#define user_read_access_begin(p, l) __user_access_begin(p, l, KUAP_READ)
+#define user_write_access_begin(p, l) __user_access_begin(p, l, KUAP_WRITE)
- might_fault();
-
- barrier_nospec();
- allow_read_from_user(ptr, len);
- return true;
-}
-#define user_read_access_begin user_read_access_begin
-#define user_read_access_end prevent_current_read_from_user
+#define user_access_end() prevent_user_access(KUAP_READ_WRITE)
+#define user_read_access_end() prevent_user_access(KUAP_READ)
+#define user_write_access_end() prevent_user_access(KUAP_WRITE)
-static __must_check __always_inline bool
-user_write_access_begin(const void __user *ptr, size_t len)
-{
- if (unlikely(!access_ok(ptr, len)))
- return false;
-
- might_fault();
-
- allow_write_to_user((void __user *)ptr, len);
- return true;
-}
-#define user_write_access_begin user_write_access_begin
-#define user_write_access_end prevent_current_write_to_user
+#define user_access_save prevent_user_access_return
+#define user_access_restore restore_user_access
#define arch_unsafe_get_user(x, p, e) do { \
__long_type(*(p)) __gu_val; \
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH v4 08/10] powerpc/32s: Fix segments setup when TASK_SIZE is not a multiple of 256M
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
` (6 preceding siblings ...)
2025-11-06 11:31 ` [PATCH v4 07/10] powerpc/uaccess: Refactor user_{read/write/}_access_begin() Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 09/10] powerpc/32: Automatically adapt TASK_SIZE based on constraints Christophe Leroy
` (2 subsequent siblings)
10 siblings, 0 replies; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
For book3s/32 it is assumed that TASK_SIZE is a multiple of 256 Mbytes,
but Kconfig allows any value for TASK_SIZE.
In all relevant calculations, align TASK_SIZE to the upper 256 Mbytes
boundary.
Also use ASM_CONST() in the definition of TASK_SIZE to ensure it is
seen as an unsigned constant.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/include/asm/book3s/32/mmu-hash.h | 5 ++++-
arch/powerpc/include/asm/task_size_32.h | 2 +-
arch/powerpc/kernel/asm-offsets.c | 2 +-
arch/powerpc/kernel/head_book3s_32.S | 6 +++---
arch/powerpc/mm/book3s32/mmu.c | 2 +-
arch/powerpc/mm/ptdump/segment_regs.c | 2 +-
6 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/32/mmu-hash.h b/arch/powerpc/include/asm/book3s/32/mmu-hash.h
index 8435bf3cdabfa..387d370c8a358 100644
--- a/arch/powerpc/include/asm/book3s/32/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/32/mmu-hash.h
@@ -192,12 +192,15 @@ extern s32 patch__hash_page_B, patch__hash_page_C;
extern s32 patch__flush_hash_A0, patch__flush_hash_A1, patch__flush_hash_A2;
extern s32 patch__flush_hash_B;
+#include <linux/sizes.h>
+#include <linux/align.h>
+
#include <asm/reg.h>
#include <asm/task_size_32.h>
static __always_inline void update_user_segment(u32 n, u32 val)
{
- if (n << 28 < TASK_SIZE)
+ if (n << 28 < ALIGN(TASK_SIZE, SZ_256M))
mtsr(val + n * 0x111, n << 28);
}
diff --git a/arch/powerpc/include/asm/task_size_32.h b/arch/powerpc/include/asm/task_size_32.h
index de7290ee770fb..30edc21f71fbd 100644
--- a/arch/powerpc/include/asm/task_size_32.h
+++ b/arch/powerpc/include/asm/task_size_32.h
@@ -6,7 +6,7 @@
#error User TASK_SIZE overlaps with KERNEL_START address
#endif
-#define TASK_SIZE (CONFIG_TASK_SIZE)
+#define TASK_SIZE ASM_CONST(CONFIG_TASK_SIZE)
/*
* This decides where the kernel will search for a free chunk of vm space during
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index a4bc80b30410a..46149f326fd42 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -331,7 +331,7 @@ int main(void)
#ifndef CONFIG_PPC64
DEFINE(TASK_SIZE, TASK_SIZE);
- DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
+ DEFINE(NUM_USER_SEGMENTS, ALIGN(TASK_SIZE, SZ_256M) >> 28);
#endif /* ! CONFIG_PPC64 */
/* datapage offsets for use by vdso */
diff --git a/arch/powerpc/kernel/head_book3s_32.S b/arch/powerpc/kernel/head_book3s_32.S
index cb2bca76be535..c1779455ea32f 100644
--- a/arch/powerpc/kernel/head_book3s_32.S
+++ b/arch/powerpc/kernel/head_book3s_32.S
@@ -420,7 +420,7 @@ InstructionTLBMiss:
lwz r2,0(r2) /* get pmd entry */
#ifdef CONFIG_EXECMEM
rlwinm r3, r0, 4, 0xf
- subi r3, r3, (TASK_SIZE >> 28) & 0xf
+ subi r3, r3, NUM_USER_SEGMENTS
#endif
rlwinm. r2,r2,0,0,19 /* extract address of pte page */
beq- InstructionAddressInvalid /* return if no mapping */
@@ -475,7 +475,7 @@ DataLoadTLBMiss:
lwz r2,0(r1) /* get pmd entry */
rlwinm r3, r0, 4, 0xf
rlwinm. r2,r2,0,0,19 /* extract address of pte page */
- subi r3, r3, (TASK_SIZE >> 28) & 0xf
+ subi r3, r3, NUM_USER_SEGMENTS
beq- 2f /* bail if no mapping */
1: rlwimi r2,r0,22,20,29 /* insert next 10 bits of address */
lwz r2,0(r2) /* get linux-style pte */
@@ -554,7 +554,7 @@ DataStoreTLBMiss:
lwz r2,0(r1) /* get pmd entry */
rlwinm r3, r0, 4, 0xf
rlwinm. r2,r2,0,0,19 /* extract address of pte page */
- subi r3, r3, (TASK_SIZE >> 28) & 0xf
+ subi r3, r3, NUM_USER_SEGMENTS
beq- 2f /* bail if no mapping */
1:
rlwimi r2,r0,22,20,29 /* insert next 10 bits of address */
diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c
index c42ecdf94e48c..37eefc6786a72 100644
--- a/arch/powerpc/mm/book3s32/mmu.c
+++ b/arch/powerpc/mm/book3s32/mmu.c
@@ -225,7 +225,7 @@ int mmu_mark_initmem_nx(void)
BUILD_BUG_ON(ALIGN_DOWN(MODULES_VADDR, SZ_256M) < TASK_SIZE);
- for (i = TASK_SIZE >> 28; i < 16; i++) {
+ for (i = ALIGN(TASK_SIZE, SZ_256M) >> 28; i < 16; i++) {
/* Do not set NX on VM space for modules */
if (is_module_segment(i << 28))
continue;
diff --git a/arch/powerpc/mm/ptdump/segment_regs.c b/arch/powerpc/mm/ptdump/segment_regs.c
index 9df3af8d481f1..c06704b18a2c8 100644
--- a/arch/powerpc/mm/ptdump/segment_regs.c
+++ b/arch/powerpc/mm/ptdump/segment_regs.c
@@ -31,7 +31,7 @@ static int sr_show(struct seq_file *m, void *v)
int i;
seq_puts(m, "---[ User Segments ]---\n");
- for (i = 0; i < TASK_SIZE >> 28; i++)
+ for (i = 0; i < ALIGN(TASK_SIZE, SZ_256M) >> 28; i++)
seg_show(m, i);
seq_puts(m, "\n---[ Kernel Segments ]---\n");
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH v4 09/10] powerpc/32: Automatically adapt TASK_SIZE based on constraints
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
` (7 preceding siblings ...)
2025-11-06 11:31 ` [PATCH v4 08/10] powerpc/32s: Fix segments setup when TASK_SIZE is not a multiple of 256M Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-06 11:31 ` [PATCH v4 10/10] powerpc/uaccess: Implement masked user access Christophe Leroy
2025-11-13 6:10 ` [PATCH v4 00/10] powerpc: " Madhavan Srinivasan
10 siblings, 0 replies; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
At the time being, TASK_SIZE can be customized by the user via Kconfig
but it is not possible to check all constraints in Kconfig. Impossible
setups are detected at compile time with BUILD_BUG() but that leads
to build failure when setting crazy values. It is not a problem on its
own because the user will usually either use the default value or set
a well thought value. However build robots generate crazy random
configs that lead to build failures, and build robots see it as a
regression every time a patch adds such a constraint.
So instead of failing the build when the custom TASK_SIZE is too
big, just adjust it to the maximum possible value matching the setup.
Several architectures already calculate TASK_SIZE based on other
parameters and options.
In order to do so, move MODULES_VADDR calculation into task_size_32.h
and ensure that:
- On book3s/32, userspace and module area have their own segments (256M)
- On 8xx, userspace has its own full PGDIR entries (4M)
Then TASK_SIZE is guaranteed to be correct so remove related
BUILD_BUG()s.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
arch/powerpc/Kconfig | 3 +--
arch/powerpc/include/asm/book3s/32/pgtable.h | 4 ---
arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 4 ---
arch/powerpc/include/asm/task_size_32.h | 26 ++++++++++++++++++++
arch/powerpc/mm/book3s32/mmu.c | 2 --
arch/powerpc/mm/mem.c | 2 --
arch/powerpc/mm/nohash/8xx.c | 2 --
7 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index e24f4d88885ae..10a8d4a5fea1f 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1292,9 +1292,8 @@ config TASK_SIZE_BOOL
Say N here unless you know what you are doing.
config TASK_SIZE
- hex "Size of user task space" if TASK_SIZE_BOOL
+ hex "Size of maximum user task space" if TASK_SIZE_BOOL
default "0x80000000" if PPC_8xx
- default "0xb0000000" if PPC_BOOK3S_32 && EXECMEM
default "0xc0000000"
config MODULES_SIZE_BOOL
diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 87dcca962be78..41ae404d0b7a6 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -195,10 +195,6 @@ void unmap_kernel_page(unsigned long va);
#define VMALLOC_END ioremap_bot
#endif
-#define MODULES_END ALIGN_DOWN(PAGE_OFFSET, SZ_256M)
-#define MODULES_SIZE (CONFIG_MODULES_SIZE * SZ_1M)
-#define MODULES_VADDR (MODULES_END - MODULES_SIZE)
-
#ifndef __ASSEMBLER__
#include <linux/sched.h>
#include <linux/threads.h>
diff --git a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
index f19115db8072f..74ad32e1588cf 100644
--- a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
@@ -170,10 +170,6 @@
#define mmu_linear_psize MMU_PAGE_8M
-#define MODULES_END PAGE_OFFSET
-#define MODULES_SIZE (CONFIG_MODULES_SIZE * SZ_1M)
-#define MODULES_VADDR (MODULES_END - MODULES_SIZE)
-
#ifndef __ASSEMBLER__
#include <linux/mmdebug.h>
diff --git a/arch/powerpc/include/asm/task_size_32.h b/arch/powerpc/include/asm/task_size_32.h
index 30edc21f71fbd..42a64bbd1964f 100644
--- a/arch/powerpc/include/asm/task_size_32.h
+++ b/arch/powerpc/include/asm/task_size_32.h
@@ -2,11 +2,37 @@
#ifndef _ASM_POWERPC_TASK_SIZE_32_H
#define _ASM_POWERPC_TASK_SIZE_32_H
+#include <linux/sizes.h>
+
#if CONFIG_TASK_SIZE > CONFIG_KERNEL_START
#error User TASK_SIZE overlaps with KERNEL_START address
#endif
+#ifdef CONFIG_PPC_8xx
+#define MODULES_END ASM_CONST(CONFIG_PAGE_OFFSET)
+#define MODULES_SIZE (CONFIG_MODULES_SIZE * SZ_1M)
+#define MODULES_VADDR (MODULES_END - MODULES_SIZE)
+#define MODULES_BASE (MODULES_VADDR & ~(UL(SZ_4M) - 1))
+#define USER_TOP MODULES_BASE
+#endif
+
+#ifdef CONFIG_PPC_BOOK3S_32
+#define MODULES_END (ASM_CONST(CONFIG_PAGE_OFFSET) & ~(UL(SZ_256M) - 1))
+#define MODULES_SIZE (CONFIG_MODULES_SIZE * SZ_1M)
+#define MODULES_VADDR (MODULES_END - MODULES_SIZE)
+#define MODULES_BASE (MODULES_VADDR & ~(UL(SZ_256M) - 1))
+#define USER_TOP MODULES_BASE
+#endif
+
+#ifndef USER_TOP
+#define USER_TOP ASM_CONST(CONFIG_PAGE_OFFSET)
+#endif
+
+#if CONFIG_TASK_SIZE < USER_TOP
#define TASK_SIZE ASM_CONST(CONFIG_TASK_SIZE)
+#else
+#define TASK_SIZE USER_TOP
+#endif
/*
* This decides where the kernel will search for a free chunk of vm space during
diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c
index 37eefc6786a72..07660e8badbda 100644
--- a/arch/powerpc/mm/book3s32/mmu.c
+++ b/arch/powerpc/mm/book3s32/mmu.c
@@ -223,8 +223,6 @@ int mmu_mark_initmem_nx(void)
update_bats();
- BUILD_BUG_ON(ALIGN_DOWN(MODULES_VADDR, SZ_256M) < TASK_SIZE);
-
for (i = ALIGN(TASK_SIZE, SZ_256M) >> 28; i < 16; i++) {
/* Do not set NX on VM space for modules */
if (is_module_segment(i << 28))
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 3ddbfdbfa9413..bc0f1a9eb0bc0 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -401,8 +401,6 @@ struct execmem_info __init *execmem_arch_setup(void)
#ifdef MODULES_VADDR
unsigned long limit = (unsigned long)_etext - SZ_32M;
- BUILD_BUG_ON(TASK_SIZE > MODULES_VADDR);
-
/* First try within 32M limit from _etext to avoid branch trampolines */
if (MODULES_VADDR < PAGE_OFFSET && MODULES_END > limit) {
start = limit;
diff --git a/arch/powerpc/mm/nohash/8xx.c b/arch/powerpc/mm/nohash/8xx.c
index ab1505cf42bf5..a9d3f4729eada 100644
--- a/arch/powerpc/mm/nohash/8xx.c
+++ b/arch/powerpc/mm/nohash/8xx.c
@@ -209,8 +209,6 @@ void __init setup_initial_memory_limit(phys_addr_t first_memblock_base,
/* 8xx can only access 32MB at the moment */
memblock_set_current_limit(min_t(u64, first_memblock_size, SZ_32M));
-
- BUILD_BUG_ON(ALIGN_DOWN(MODULES_VADDR, PGDIR_SIZE) < TASK_SIZE);
}
int pud_clear_huge(pud_t *pud)
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH v4 10/10] powerpc/uaccess: Implement masked user access
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
` (8 preceding siblings ...)
2025-11-06 11:31 ` [PATCH v4 09/10] powerpc/32: Automatically adapt TASK_SIZE based on constraints Christophe Leroy
@ 2025-11-06 11:31 ` Christophe Leroy
2025-11-06 12:35 ` Peter Zijlstra
2025-11-13 6:10 ` [PATCH v4 00/10] powerpc: " Madhavan Srinivasan
10 siblings, 1 reply; 18+ messages in thread
From: Christophe Leroy @ 2025-11-06 11:31 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: Christophe Leroy, linux-block, linux-fsdevel, linux-kernel,
netdev, linuxppc-dev
Masked user access avoids the address/size verification by access_ok().
Allthough its main purpose is to skip the speculation in the
verification of user address and size hence avoid the need of spec
mitigation, it also has the advantage of reducing the amount of
instructions required so it even benefits to platforms that don't
need speculation mitigation, especially when the size of the copy is
not know at build time.
So implement masked user access on powerpc. The only requirement is
to have memory gap that faults between the top user space and the
real start of kernel area.
On 64 bits platforms the address space is divided that way:
0xffffffffffffffff +------------------+
| |
| kernel space |
| |
0xc000000000000000 +------------------+ <== PAGE_OFFSET
|//////////////////|
|//////////////////|
0x8000000000000000 |//////////////////|
|//////////////////|
|//////////////////|
0x0010000000000000 +------------------+ <== TASK_SIZE_MAX
| |
| user space |
| |
0x0000000000000000 +------------------+
Kernel is always above 0x8000000000000000 and user always
below, with a gap in-between. It leads to a 3 instructions sequence:
150: 7c 69 fe 76 sradi r9,r3,63
154: 79 29 00 40 clrldi r9,r9,1
158: 7c 63 48 78 andc r3,r3,r9
This sequence leaves r3 unmodified when it is below 0x8000000000000000
and clamps it to 0x8000000000000000 if it is above.
On 32 bits it is more tricky. In theory user space can go up to
0xbfffffff while kernel will usually start at 0xc0000000. So a gap
needs to be added in-between. Allthough in theory a single 4k page
would suffice, it is easier and more efficient to enforce a 128k gap
below kernel, as it simplifies the masking.
e500 has the isel instruction which allows selecting one value or
the other without branch and that instruction is not speculative, so
use it. Allthough GCC usually generates code using that instruction,
it is safer to use inline assembly to be sure. The result is:
14: 3d 20 bf fe lis r9,-16386
18: 7c 03 48 40 cmplw r3,r9
1c: 7c 69 18 5e iselgt r3,r9,r3
On other ones, when kernel space is over 0x80000000 and user space
is below, the logic in mask_user_address_simple() leads to a
3 instruction sequence:
64: 7c 69 fe 70 srawi r9,r3,31
68: 55 29 00 7e clrlwi r9,r9,1
6c: 7c 63 48 78 andc r3,r3,r9
This is the default on powerpc 8xx.
When the limit between user space and kernel space is not 0x80000000,
mask_user_address_32() is used and a 6 instructions sequence is
generated:
24: 54 69 7c 7e srwi r9,r3,17
28: 21 29 57 ff subfic r9,r9,22527
2c: 7d 29 fe 70 srawi r9,r9,31
30: 75 2a b0 00 andis. r10,r9,45056
34: 7c 63 48 78 andc r3,r3,r9
38: 7c 63 53 78 or r3,r3,r10
The constraint is that TASK_SIZE be aligned to 128K in order to get
the most optimal number of instructions.
When CONFIG_PPC_BARRIER_NOSPEC is not defined, fallback on the
test-based masking as it is quicker than the 6 instructions sequence
but not quicker than the 3 instructions sequences above.
As an exemple, allthough barrier_nospec() voids on the 8xx, this
change has the following impact on strncpy_from_user(): the length of
the function is reduced from 488 to 340 bytes:
Start of the function with the patch:
00000000 <strncpy_from_user>:
0: 7c ab 2b 79 mr. r11,r5
4: 40 81 01 40 ble 144 <strncpy_from_user+0x144>
8: 7c 89 fe 70 srawi r9,r4,31
c: 55 29 00 7e clrlwi r9,r9,1
10: 7c 84 48 78 andc r4,r4,r9
14: 3d 20 dc 00 lis r9,-9216
18: 7d 3a c3 a6 mtspr 794,r9
1c: 2f 8b 00 03 cmpwi cr7,r11,3
20: 40 9d 00 b4 ble cr7,d4 <strncpy_from_user+0xd4>
...
Start of the function without the patch:
00000000 <strncpy_from_user>:
0: 7c a0 2b 79 mr. r0,r5
4: 40 81 01 10 ble 114 <strncpy_from_user+0x114>
8: 2f 84 00 00 cmpwi cr7,r4,0
c: 41 9c 01 30 blt cr7,13c <strncpy_from_user+0x13c>
10: 3d 20 80 00 lis r9,-32768
14: 7d 24 48 50 subf r9,r4,r9
18: 7f 80 48 40 cmplw cr7,r0,r9
1c: 7c 05 03 78 mr r5,r0
20: 41 9d 01 00 bgt cr7,120 <strncpy_from_user+0x120>
24: 3d 20 80 00 lis r9,-32768
28: 7d 25 48 50 subf r9,r5,r9
2c: 7f 84 48 40 cmplw cr7,r4,r9
30: 38 e0 ff f2 li r7,-14
34: 41 9d 00 e4 bgt cr7,118 <strncpy_from_user+0x118>
38: 94 21 ff e0 stwu r1,-32(r1)
3c: 3d 20 dc 00 lis r9,-9216
40: 7d 3a c3 a6 mtspr 794,r9
44: 2b 85 00 03 cmplwi cr7,r5,3
48: 40 9d 01 6c ble cr7,1b4 <strncpy_from_user+0x1b4>
...
118: 7c e3 3b 78 mr r3,r7
11c: 4e 80 00 20 blr
120: 7d 25 4b 78 mr r5,r9
124: 3d 20 80 00 lis r9,-32768
128: 7d 25 48 50 subf r9,r5,r9
12c: 7f 84 48 40 cmplw cr7,r4,r9
130: 38 e0 ff f2 li r7,-14
134: 41 bd ff e4 bgt cr7,118 <strncpy_from_user+0x118>
138: 4b ff ff 00 b 38 <strncpy_from_user+0x38>
13c: 38 e0 ff f2 li r7,-14
140: 4b ff ff d8 b 118 <strncpy_from_user+0x118>
...
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v4: Rebase on top of core-scoped-uaccess tag and simplified as suggested by Gabriel
v3: Rewrite mask_user_address_simple() for a smaller result on powerpc64, suggested by Gabriel
v2: Added 'likely()' to the test in mask_user_address_fallback()
---
arch/powerpc/include/asm/task_size_32.h | 6 +-
arch/powerpc/include/asm/uaccess.h | 76 +++++++++++++++++++++++++
2 files changed, 79 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/asm/task_size_32.h b/arch/powerpc/include/asm/task_size_32.h
index 42a64bbd1964f..725ddbf06217f 100644
--- a/arch/powerpc/include/asm/task_size_32.h
+++ b/arch/powerpc/include/asm/task_size_32.h
@@ -13,7 +13,7 @@
#define MODULES_SIZE (CONFIG_MODULES_SIZE * SZ_1M)
#define MODULES_VADDR (MODULES_END - MODULES_SIZE)
#define MODULES_BASE (MODULES_VADDR & ~(UL(SZ_4M) - 1))
-#define USER_TOP MODULES_BASE
+#define USER_TOP (MODULES_BASE - SZ_4M)
#endif
#ifdef CONFIG_PPC_BOOK3S_32
@@ -21,11 +21,11 @@
#define MODULES_SIZE (CONFIG_MODULES_SIZE * SZ_1M)
#define MODULES_VADDR (MODULES_END - MODULES_SIZE)
#define MODULES_BASE (MODULES_VADDR & ~(UL(SZ_256M) - 1))
-#define USER_TOP MODULES_BASE
+#define USER_TOP (MODULES_BASE - SZ_4M)
#endif
#ifndef USER_TOP
-#define USER_TOP ASM_CONST(CONFIG_PAGE_OFFSET)
+#define USER_TOP ((ASM_CONST(CONFIG_PAGE_OFFSET) - SZ_128K) & ~(UL(SZ_128K) - 1))
#endif
#if CONFIG_TASK_SIZE < USER_TOP
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index 721d65dbbb2e5..ba1d878c3f404 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -2,6 +2,8 @@
#ifndef _ARCH_POWERPC_UACCESS_H
#define _ARCH_POWERPC_UACCESS_H
+#include <linux/sizes.h>
+
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/extable.h>
@@ -435,6 +437,80 @@ static __must_check __always_inline bool __user_access_begin(const void __user *
#define user_access_save prevent_user_access_return
#define user_access_restore restore_user_access
+/*
+ * Masking the user address is an alternative to a conditional
+ * user_access_begin that can avoid the fencing. This only works
+ * for dense accesses starting at the address.
+ */
+static inline void __user *mask_user_address_simple(const void __user *ptr)
+{
+ unsigned long addr = (unsigned long)ptr;
+ unsigned long mask = (unsigned long)(((long)addr >> (BITS_PER_LONG - 1)) & LONG_MAX);
+
+ return (void __user *)(addr & ~mask);
+}
+
+static inline void __user *mask_user_address_isel(const void __user *ptr)
+{
+ unsigned long addr;
+
+ asm("cmplw %1, %2; iselgt %0, %2, %1" : "=r"(addr) : "r"(ptr), "r"(TASK_SIZE) : "cr0");
+
+ return (void __user *)addr;
+}
+
+/* TASK_SIZE is a multiple of 128K for shifting by 17 to the right */
+static inline void __user *mask_user_address_32(const void __user *ptr)
+{
+ unsigned long addr = (unsigned long)ptr;
+ unsigned long mask = (unsigned long)((long)((TASK_SIZE >> 17) - 1 - (addr >> 17)) >> 31);
+
+ addr = (addr & ~mask) | (TASK_SIZE & mask);
+
+ return (void __user *)addr;
+}
+
+static inline void __user *mask_user_address_fallback(const void __user *ptr)
+{
+ unsigned long addr = (unsigned long)ptr;
+
+ return (void __user *)(likely(addr < TASK_SIZE) ? addr : TASK_SIZE);
+}
+
+static inline void __user *mask_user_address(const void __user *ptr)
+{
+#ifdef MODULES_VADDR
+ const unsigned long border = MODULES_VADDR;
+#else
+ const unsigned long border = PAGE_OFFSET;
+#endif
+
+ if (IS_ENABLED(CONFIG_PPC64))
+ return mask_user_address_simple(ptr);
+ if (IS_ENABLED(CONFIG_E500))
+ return mask_user_address_isel(ptr);
+ if (TASK_SIZE <= UL(SZ_2G) && border >= UL(SZ_2G))
+ return mask_user_address_simple(ptr);
+ if (IS_ENABLED(CONFIG_PPC_BARRIER_NOSPEC))
+ return mask_user_address_32(ptr);
+ return mask_user_address_fallback(ptr);
+}
+
+static __always_inline void __user *__masked_user_access_begin(const void __user *p,
+ unsigned long dir)
+{
+ void __user *ptr = mask_user_address(p);
+
+ might_fault();
+ allow_user_access(ptr, dir);
+
+ return ptr;
+}
+
+#define masked_user_access_begin(p) __masked_user_access_begin(p, KUAP_READ_WRITE)
+#define masked_user_read_access_begin(p) __masked_user_access_begin(p, KUAP_READ)
+#define masked_user_write_access_begin(p) __masked_user_access_begin(p, KUAP_WRITE)
+
#define arch_unsafe_get_user(x, p, e) do { \
__long_type(*(p)) __gu_val; \
__typeof__(*(p)) __user *__gu_addr = (p); \
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v4 10/10] powerpc/uaccess: Implement masked user access
2025-11-06 11:31 ` [PATCH v4 10/10] powerpc/uaccess: Implement masked user access Christophe Leroy
@ 2025-11-06 12:35 ` Peter Zijlstra
2025-11-06 13:42 ` David Laight
0 siblings, 1 reply; 18+ messages in thread
From: Peter Zijlstra @ 2025-11-06 12:35 UTC (permalink / raw)
To: Christophe Leroy
Cc: Alexander Viro, Christian Brauner, Jan Kara, Thomas Gleixner,
Ingo Molnar, Darren Hart, Davidlohr Bueso, Andre Almeida,
Andrew Morton, Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni,
Willem de Bruijn, David S. Miller, Jakub Kicinski, Simon Horman,
Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin, linux-block, linux-fsdevel,
linux-kernel, netdev, linuxppc-dev
On Thu, Nov 06, 2025 at 12:31:28PM +0100, Christophe Leroy wrote:
> On 32 bits it is more tricky. In theory user space can go up to
> 0xbfffffff while kernel will usually start at 0xc0000000. So a gap
> needs to be added in-between. Allthough in theory a single 4k page
> would suffice, it is easier and more efficient to enforce a 128k gap
> below kernel, as it simplifies the masking.
Do we have the requirement that the first access of a masked pointer is
within 4k of the initial address?
Suppose the pointer is to an 16k array, and the memcpy happens to like
going backwards. Then a 4k hole just won't do.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 10/10] powerpc/uaccess: Implement masked user access
2025-11-06 12:35 ` Peter Zijlstra
@ 2025-11-06 13:42 ` David Laight
0 siblings, 0 replies; 18+ messages in thread
From: David Laight @ 2025-11-06 13:42 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Christophe Leroy, Alexander Viro, Christian Brauner, Jan Kara,
Thomas Gleixner, Ingo Molnar, Darren Hart, Davidlohr Bueso,
Andre Almeida, Andrew Morton, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S. Miller, Jakub Kicinski,
Simon Horman, Daniel Borkmann, Dave Hansen, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin, linux-block, linux-fsdevel,
linux-kernel, netdev, linuxppc-dev
On Thu, 6 Nov 2025 13:35:50 +0100
Peter Zijlstra <peterz@infradead.org> wrote:
> On Thu, Nov 06, 2025 at 12:31:28PM +0100, Christophe Leroy wrote:
>
> > On 32 bits it is more tricky. In theory user space can go up to
> > 0xbfffffff while kernel will usually start at 0xc0000000. So a gap
> > needs to be added in-between. Allthough in theory a single 4k page
Although
> > would suffice, it is easier and more efficient to enforce a 128k gap
> > below kernel, as it simplifies the masking.
>
> Do we have the requirement that the first access of a masked pointer is
> within 4k of the initial address?
>
> Suppose the pointer is to an 16k array, and the memcpy happens to like
> going backwards. Then a 4k hole just won't do.
I think that requiring the accesses be within 4k of the base (or previous
access) is a reasonable restriction.
It is something that needs verifying before code is changed to use
these accessors.
Documenting a big gap is almost more likely to lead to errors!
If 128k is ok, no one is really going to notice code that might
offset by 130k.
OTOH if the (documented) limit is 256 bytes then you don't have to be
careful about accessing structures sequentially, and can safely realign
pointers.
I suspect the mk-1 brain treats 4k and 256 as muchthe same value.
Requiring fully sequential accesses (which the original x86-64 required
because it converted kernel addresses to ~0) would require policing by
the compiler - I tried it once, it horrid.
David
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 00/10] powerpc: Implement masked user access
2025-11-06 11:31 [PATCH v4 00/10] powerpc: Implement masked user access Christophe Leroy
` (9 preceding siblings ...)
2025-11-06 11:31 ` [PATCH v4 10/10] powerpc/uaccess: Implement masked user access Christophe Leroy
@ 2025-11-13 6:10 ` Madhavan Srinivasan
10 siblings, 0 replies; 18+ messages in thread
From: Madhavan Srinivasan @ 2025-11-13 6:10 UTC (permalink / raw)
To: Christophe Leroy, Alexander Viro, Christian Brauner, Jan Kara,
Thomas Gleixner, Ingo Molnar, Peter Zijlstra, Darren Hart,
Davidlohr Bueso, Andre Almeida, Andrew Morton, Eric Dumazet,
Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn, David S. Miller,
Jakub Kicinski, Simon Horman, Daniel Borkmann, Dave Hansen,
Michael Ellerman, Nicholas Piggin
Cc: linux-block, linux-fsdevel, linux-kernel, netdev, linuxppc-dev
On 11/6/25 5:01 PM, Christophe Leroy wrote:
> This is a rebase on top of commit 6ec821f050e2 (tag: core-scoped-uaccess)
> from tip tree.
>
> Thomas, Peter, could you please take non-powerpc patches (1, 2, 3)
> in tip tree for v6.19, then Maddy will take powerpc patches (4-10)
> into powerpc-next for v6.20.
Thomas/Peter,
If you can please take non-powerpc patches in this series
in v6.19, I will park the rest of the series (4-10)
to the v6.20 merge.
Maddy
>
> Masked user access avoids the address/size verification by access_ok().
> Allthough its main purpose is to skip the speculation in the
> verification of user address and size hence avoid the need of spec
> mitigation, it also has the advantage to reduce the amount of
> instructions needed so it also benefits to platforms that don't
> need speculation mitigation, especially when the size of the copy is
> not know at build time.
>
> Patches 1,2,4 are cleaning up some redundant barrier_nospec()
> introduced by commit 74e19ef0ff80 ("uaccess: Add speculation barrier
> to copy_from_user()"). To do that, a speculation barrier is added to
> copy_from_user_iter() so that the barrier in powerpc raw_copy_from_user()
> which is redundant with the one in copy_from_user() can be removed. To
> avoid impacting x86, copy_from_user_iter() is first converted to using
> masked user access.
>
> Patch 3 replaces wrong calls to masked_user_access_begin() with calls
> to masked_user_read_access_begin() and masked_user_write_access_begin()
> to match with user_read_access_end() and user_write_access_end().
>
> Patches 5,6,7 are cleaning up powerpc uaccess functions.
>
> Patches 8 and 9 prepare powerpc/32 for the necessary gap at the top
> of userspace.
>
> Last patch implements masked user access.
>
> Changes in v4:
> - Rebased on top of commit 6ec821f050e2 (tag: core-scoped-uaccess) from tip tree
> - Patch 3: Simplified as masked_user_read_access_begin() and masked_user_write_access_begin() are already there.
> - Patch 10: Simplified mask_user_address_simple() as suggested by Gabriel.
>
> Changes in v3:
> - Rebased on top of v6.18-rc1
> - Patch 3: Impact on recently modified net/core/scm.c
> - Patch 10: Rewrite mask_user_address_simple() for a smaller result on powerpc64, suggested by Gabriel
>
> Changes in v2:
> - Converted copy_from_user_iter() to using masked user access.
> - Cleaned up powerpc uaccess function to minimise code duplication
> when adding masked user access
> - Automated TASK_SIZE calculation to minimise use of BUILD_BUG_ON()
> - Tried to make some commit messages more clean based on feedback from
> version 1 of the series.
>
> Christophe Leroy (10):
> iter: Avoid barrier_nospec() in copy_from_user_iter()
> uaccess: Add speculation barrier to copy_from_user_iter()
> uaccess: Use masked_user_{read/write}_access_begin when required
> powerpc/uaccess: Move barrier_nospec() out of
> allow_read_{from/write}_user()
> powerpc/uaccess: Remove unused size and from parameters from
> allow_access_user()
> powerpc/uaccess: Remove
> {allow/prevent}_{read/write/read_write}_{from/to/}_user()
> powerpc/uaccess: Refactor user_{read/write/}_access_begin()
> powerpc/32s: Fix segments setup when TASK_SIZE is not a multiple of
> 256M
> powerpc/32: Automatically adapt TASK_SIZE based on constraints
> powerpc/uaccess: Implement masked user access
>
> arch/powerpc/Kconfig | 3 +-
> arch/powerpc/include/asm/barrier.h | 2 +-
> arch/powerpc/include/asm/book3s/32/kup.h | 3 +-
> arch/powerpc/include/asm/book3s/32/mmu-hash.h | 5 +-
> arch/powerpc/include/asm/book3s/32/pgtable.h | 4 -
> arch/powerpc/include/asm/book3s/64/kup.h | 6 +-
> arch/powerpc/include/asm/kup.h | 52 +------
> arch/powerpc/include/asm/nohash/32/kup-8xx.h | 3 +-
> arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 4 -
> arch/powerpc/include/asm/nohash/kup-booke.h | 3 +-
> arch/powerpc/include/asm/task_size_32.h | 28 +++-
> arch/powerpc/include/asm/uaccess.h | 132 +++++++++++++-----
> arch/powerpc/kernel/asm-offsets.c | 2 +-
> arch/powerpc/kernel/head_book3s_32.S | 6 +-
> arch/powerpc/mm/book3s32/mmu.c | 4 +-
> arch/powerpc/mm/mem.c | 2 -
> arch/powerpc/mm/nohash/8xx.c | 2 -
> arch/powerpc/mm/ptdump/segment_regs.c | 2 +-
> lib/iov_iter.c | 22 ++-
> lib/strncpy_from_user.c | 2 +-
> lib/strnlen_user.c | 2 +-
> net/core/scm.c | 2 +-
> 22 files changed, 161 insertions(+), 130 deletions(-)
>
^ permalink raw reply [flat|nested] 18+ messages in thread