LinuxPPC-Dev Archive mirror
 help / color / mirror / Atom feed
* [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall
@ 2018-08-21 18:42 Breno Leitao
  2024-03-12  8:17 ` Christophe Leroy
  0 siblings, 1 reply; 8+ messages in thread
From: Breno Leitao @ 2018-08-21 18:42 UTC (permalink / raw
  To: linuxppc-dev; +Cc: Breno Leitao

The rtas syscall reads a value from a user-provided structure and uses it
to index an array, being a possible area for a potential spectre v1 attack.
This is the code that exposes this problem.

	args.rets = &args.args[nargs];

The nargs is an user provided value, and the below code is an example where
the 'nargs' value would be set to XX.

	struct rtas_args ra;
	ra.nargs = htobe32(XX);
	syscall(__NR_rtas, &ra);

Signed-off-by: Breno Leitao <leitao@debian.org>
---
 arch/powerpc/kernel/rtas.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 8afd146bc9c7..5ef3c863003d 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/reboot.h>
 #include <linux/syscalls.h>
+#include <linux/nospec.h>
 
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -1056,7 +1057,7 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
 	struct rtas_args args;
 	unsigned long flags;
 	char *buff_copy, *errbuf = NULL;
-	int nargs, nret, token;
+	int index, nargs, nret, token;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -1084,7 +1085,8 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
 	if (token == RTAS_UNKNOWN_SERVICE)
 		return -EINVAL;
 
-	args.rets = &args.args[nargs];
+	index = array_index_nospec(nargs, ARRAY_SIZE(args.args));
+	args.rets = &args.args[index];
 	memset(args.rets, 0, nret * sizeof(rtas_arg_t));
 
 	/* Need to handle ibm,suspend_me call specially */
-- 
2.16.3

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall
  2018-08-21 18:42 [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall Breno Leitao
@ 2024-03-12  8:17 ` Christophe Leroy
  2024-03-12  9:05   ` Breno Leitao
  0 siblings, 1 reply; 8+ messages in thread
From: Christophe Leroy @ 2024-03-12  8:17 UTC (permalink / raw
  To: Breno Leitao, linuxppc-dev@lists.ozlabs.org, Nathan Lynch

+Nathan as this is RTAS related.

Le 21/08/2018 à 20:42, Breno Leitao a écrit :
> The rtas syscall reads a value from a user-provided structure and uses it
> to index an array, being a possible area for a potential spectre v1 attack.
> This is the code that exposes this problem.
> 
> 	args.rets = &args.args[nargs];
> 
> The nargs is an user provided value, and the below code is an example where
> the 'nargs' value would be set to XX.
> 
> 	struct rtas_args ra;
> 	ra.nargs = htobe32(XX);
> 	syscall(__NR_rtas, &ra);


This patch has been hanging around in patchwork since 2018 and doesn't 
apply anymore. Is it still relevant ? If so, can you rebase et resubmit ?

Thanks
Christophe


> 
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
>   arch/powerpc/kernel/rtas.c | 6 ++++--
>   1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
> index 8afd146bc9c7..5ef3c863003d 100644
> --- a/arch/powerpc/kernel/rtas.c
> +++ b/arch/powerpc/kernel/rtas.c
> @@ -27,6 +27,7 @@
>   #include <linux/slab.h>
>   #include <linux/reboot.h>
>   #include <linux/syscalls.h>
> +#include <linux/nospec.h>
>   
>   #include <asm/prom.h>
>   #include <asm/rtas.h>
> @@ -1056,7 +1057,7 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
>   	struct rtas_args args;
>   	unsigned long flags;
>   	char *buff_copy, *errbuf = NULL;
> -	int nargs, nret, token;
> +	int index, nargs, nret, token;
>   
>   	if (!capable(CAP_SYS_ADMIN))
>   		return -EPERM;
> @@ -1084,7 +1085,8 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
>   	if (token == RTAS_UNKNOWN_SERVICE)
>   		return -EINVAL;
>   
> -	args.rets = &args.args[nargs];
> +	index = array_index_nospec(nargs, ARRAY_SIZE(args.args));
> +	args.rets = &args.args[index];
>   	memset(args.rets, 0, nret * sizeof(rtas_arg_t));
>   
>   	/* Need to handle ibm,suspend_me call specially */

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall
  2024-03-12  8:17 ` Christophe Leroy
@ 2024-03-12  9:05   ` Breno Leitao
  2024-03-12 11:07     ` Michael Ellerman
  0 siblings, 1 reply; 8+ messages in thread
From: Breno Leitao @ 2024-03-12  9:05 UTC (permalink / raw
  To: Christophe Leroy; +Cc: Nathan Lynch, linuxppc-dev@lists.ozlabs.org

On Tue, Mar 12, 2024 at 08:17:42AM +0000, Christophe Leroy wrote:
> +Nathan as this is RTAS related.
> 
> Le 21/08/2018 à 20:42, Breno Leitao a écrit :
> > The rtas syscall reads a value from a user-provided structure and uses it
> > to index an array, being a possible area for a potential spectre v1 attack.
> > This is the code that exposes this problem.
> > 
> > 	args.rets = &args.args[nargs];
> > 
> > The nargs is an user provided value, and the below code is an example where
> > the 'nargs' value would be set to XX.
> > 
> > 	struct rtas_args ra;
> > 	ra.nargs = htobe32(XX);
> > 	syscall(__NR_rtas, &ra);
> 
> 
> This patch has been hanging around in patchwork since 2018 and doesn't 
> apply anymore. Is it still relevant ? If so, can you rebase et resubmit ?

This seems to be important, since nargs is a user-provided value. I can
submit it if the maintainers are willing to accept. I do not want to
spend my time if no one is willing to review it.

Thanks for revamping this one.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall
  2024-03-12  9:05   ` Breno Leitao
@ 2024-03-12 11:07     ` Michael Ellerman
  2024-03-12 13:10       ` Breno Leitao
  2024-03-18 15:25       ` Nathan Lynch
  0 siblings, 2 replies; 8+ messages in thread
From: Michael Ellerman @ 2024-03-12 11:07 UTC (permalink / raw
  To: Breno Leitao, Christophe Leroy
  Cc: Nathan Lynch, linuxppc-dev@lists.ozlabs.org

Breno Leitao <leitao@debian.org> writes:
> On Tue, Mar 12, 2024 at 08:17:42AM +0000, Christophe Leroy wrote:
>> +Nathan as this is RTAS related.
>> 
>> Le 21/08/2018 à 20:42, Breno Leitao a écrit :
>> > The rtas syscall reads a value from a user-provided structure and uses it
>> > to index an array, being a possible area for a potential spectre v1 attack.
>> > This is the code that exposes this problem.
>> > 
>> > 	args.rets = &args.args[nargs];
>> > 
>> > The nargs is an user provided value, and the below code is an example where
>> > the 'nargs' value would be set to XX.
>> > 
>> > 	struct rtas_args ra;
>> > 	ra.nargs = htobe32(XX);
>> > 	syscall(__NR_rtas, &ra);
>> 
>> 
>> This patch has been hanging around in patchwork since 2018 and doesn't 
>> apply anymore. Is it still relevant ? If so, can you rebase et resubmit ?
>
> This seems to be important, since nargs is a user-provided value. I can
> submit it if the maintainers are willing to accept. I do not want to
> spend my time if no one is willing to review it.

My memory is that I didn't think it was actually a problem, because all
we do is memset args.rets to zero. I thought I'd talked to you on Slack
about it, but maybe I didn't.

Anyway we should probably just fix it to be safe and keep the static
checkers happy.

I'll rebase it and apply it, I'm sure you've got better things to do :)

cheers

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall
  2024-03-12 11:07     ` Michael Ellerman
@ 2024-03-12 13:10       ` Breno Leitao
  2024-03-18 15:25       ` Nathan Lynch
  1 sibling, 0 replies; 8+ messages in thread
From: Breno Leitao @ 2024-03-12 13:10 UTC (permalink / raw
  To: Michael Ellerman; +Cc: Nathan Lynch, linuxppc-dev@lists.ozlabs.org

On Tue, Mar 12, 2024 at 10:07:54PM +1100, Michael Ellerman wrote:
> Breno Leitao <leitao@debian.org> writes:
> > On Tue, Mar 12, 2024 at 08:17:42AM +0000, Christophe Leroy wrote:
> >> +Nathan as this is RTAS related.
> >> 
> >> Le 21/08/2018 à 20:42, Breno Leitao a écrit :
> >> > The rtas syscall reads a value from a user-provided structure and uses it
> >> > to index an array, being a possible area for a potential spectre v1 attack.
> >> > This is the code that exposes this problem.
> >> > 
> >> > 	args.rets = &args.args[nargs];
> >> > 
> >> > The nargs is an user provided value, and the below code is an example where
> >> > the 'nargs' value would be set to XX.
> >> > 
> >> > 	struct rtas_args ra;
> >> > 	ra.nargs = htobe32(XX);
> >> > 	syscall(__NR_rtas, &ra);
> >> 
> >> 
> >> This patch has been hanging around in patchwork since 2018 and doesn't 
> >> apply anymore. Is it still relevant ? If so, can you rebase et resubmit ?
> >
> > This seems to be important, since nargs is a user-provided value. I can
> > submit it if the maintainers are willing to accept. I do not want to
> > spend my time if no one is willing to review it.
> 
> My memory is that I didn't think it was actually a problem, because all
> we do is memset args.rets to zero. I thought I'd talked to you on Slack
> about it, but maybe I didn't.
> 
> Anyway we should probably just fix it to be safe and keep the static
> checkers happy.
> 
> I'll rebase it and apply it, I'm sure you've got better things to do :)

Awesome. Thanks Michael!

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall
  2024-03-12 11:07     ` Michael Ellerman
  2024-03-12 13:10       ` Breno Leitao
@ 2024-03-18 15:25       ` Nathan Lynch
  2024-05-21  1:23         ` Michael Ellerman
  1 sibling, 1 reply; 8+ messages in thread
From: Nathan Lynch @ 2024-03-18 15:25 UTC (permalink / raw
  To: Michael Ellerman, Breno Leitao, Christophe Leroy
  Cc: linuxppc-dev@lists.ozlabs.org

Michael Ellerman <mpe@ellerman.id.au> writes:

> Breno Leitao <leitao@debian.org> writes:
>> On Tue, Mar 12, 2024 at 08:17:42AM +0000, Christophe Leroy wrote:
>>> +Nathan as this is RTAS related.

Thanks!

>>> Le 21/08/2018 à 20:42, Breno Leitao a écrit :
>>> > The rtas syscall reads a value from a user-provided structure and uses it
>>> > to index an array, being a possible area for a potential spectre v1 attack.
>>> > This is the code that exposes this problem.
>>> > 
>>> > 	args.rets = &args.args[nargs];
>>> > 
>>> > The nargs is an user provided value, and the below code is an example where
>>> > the 'nargs' value would be set to XX.
>>> > 
>>> > 	struct rtas_args ra;
>>> > 	ra.nargs = htobe32(XX);
>>> > 	syscall(__NR_rtas, &ra);
>>> 
>>> 
>>> This patch has been hanging around in patchwork since 2018 and doesn't 
>>> apply anymore. Is it still relevant ? If so, can you rebase et resubmit ?
>>
>> This seems to be important, since nargs is a user-provided value. I can
>> submit it if the maintainers are willing to accept. I do not want to
>> spend my time if no one is willing to review it.
>
> My memory is that I didn't think it was actually a problem, because all
> we do is memset args.rets to zero.

This is also my initial reaction to this. I suppose if the memset()
implementation performs some validation of the destination buffer
contents (comparing to a known poison value or something) that could
load the CPU cache then there is a more plausible issue?

> Anyway we should probably just fix it to be safe and keep the static
> checkers happy.

Here is the relevant passage in its current state:

        if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0)
                return -EFAULT;

        nargs = be32_to_cpu(args.nargs);
        nret  = be32_to_cpu(args.nret);
        token = be32_to_cpu(args.token);

        if (nargs >= ARRAY_SIZE(args.args)
            || nret > ARRAY_SIZE(args.args)
            || nargs + nret > ARRAY_SIZE(args.args))
                return -EINVAL;

        /* Copy in args. */
        if (copy_from_user(args.args, uargs->args,
                           nargs * sizeof(rtas_arg_t)) != 0)
                return -EFAULT;

        /*
         * If this token doesn't correspond to a function the kernel
         * understands, you're not allowed to call it.
         */
        func = rtas_token_to_function_untrusted(token);
        if (!func)
                return -EINVAL;

        args.rets = &args.args[nargs];
        memset(args.rets, 0, nret * sizeof(rtas_arg_t));

Some questions:

1. The patch sanitizes 'nargs' immediately before the call to memset(),
   but shouldn't that happen before 'nargs' is used as an input to
   copy_from_user()?

2. If 'nargs' needs this treatment, then why wouldn't the user-supplied
   'nret' and 'token' need them as well? 'nret' is used to index the
   same array as 'nargs'. And at least conceptually, 'token' is used to
   index a data structure (xarray) with array-like semantics (to be
   fair, this is a relatively recent development and was not the case
   when this change was submitted).

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall
  2024-03-18 15:25       ` Nathan Lynch
@ 2024-05-21  1:23         ` Michael Ellerman
  2024-05-31  0:35           ` Nathan Lynch
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Ellerman @ 2024-05-21  1:23 UTC (permalink / raw
  To: Nathan Lynch, Breno Leitao, Christophe Leroy
  Cc: linuxppc-dev@lists.ozlabs.org

Nathan Lynch <nathanl@linux.ibm.com> writes:
> Michael Ellerman <mpe@ellerman.id.au> writes:
>> Breno Leitao <leitao@debian.org> writes:
>>> On Tue, Mar 12, 2024 at 08:17:42AM +0000, Christophe Leroy wrote:
>>>> +Nathan as this is RTAS related.
>
> Thanks!
>
>>>> Le 21/08/2018 à 20:42, Breno Leitao a écrit :
>>>> > The rtas syscall reads a value from a user-provided structure and uses it
>>>> > to index an array, being a possible area for a potential spectre v1 attack.
>>>> > This is the code that exposes this problem.
>>>> > 
>>>> > 	args.rets = &args.args[nargs];
>>>> > 
>>>> > The nargs is an user provided value, and the below code is an example where
>>>> > the 'nargs' value would be set to XX.
>>>> > 
>>>> > 	struct rtas_args ra;
>>>> > 	ra.nargs = htobe32(XX);
>>>> > 	syscall(__NR_rtas, &ra);
>>>> 
>>>> 
>>>> This patch has been hanging around in patchwork since 2018 and doesn't 
>>>> apply anymore. Is it still relevant ? If so, can you rebase et resubmit ?
>>>
>>> This seems to be important, since nargs is a user-provided value. I can
>>> submit it if the maintainers are willing to accept. I do not want to
>>> spend my time if no one is willing to review it.
>>
>> My memory is that I didn't think it was actually a problem, because all
>> we do is memset args.rets to zero.
>
> This is also my initial reaction to this. I suppose if the memset()
> implementation performs some validation of the destination buffer
> contents (comparing to a known poison value or something) that could
> load the CPU cache then there is a more plausible issue?

Yeah I guess that's possible.

In the past my approach to these was to analyse the exploitability of
each case and only patch those where there was a feasible case to be
made.

But I think that was wrong, doing that analysis is too time consuming at
scale, is easy to get wrong, and is also fragile in the face of the code
changing.

Especially in cases like this where the performance cost of the checks
is going to be dwarfed by other factors like syscall/firmware overhead.

>> Anyway we should probably just fix it to be safe and keep the static
>> checkers happy.
>
> Here is the relevant passage in its current state:
>
>         if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0)
>                 return -EFAULT;
>
>         nargs = be32_to_cpu(args.nargs);
>         nret  = be32_to_cpu(args.nret);
>         token = be32_to_cpu(args.token);
>
>         if (nargs >= ARRAY_SIZE(args.args)
>             || nret > ARRAY_SIZE(args.args)
>             || nargs + nret > ARRAY_SIZE(args.args))
>                 return -EINVAL;
>
>         /* Copy in args. */
>         if (copy_from_user(args.args, uargs->args,
>                            nargs * sizeof(rtas_arg_t)) != 0)
>                 return -EFAULT;
>
>         /*
>          * If this token doesn't correspond to a function the kernel
>          * understands, you're not allowed to call it.
>          */
>         func = rtas_token_to_function_untrusted(token);
>         if (!func)
>                 return -EINVAL;
>
>         args.rets = &args.args[nargs];
>         memset(args.rets, 0, nret * sizeof(rtas_arg_t));
>
> Some questions:
>
> 1. The patch sanitizes 'nargs' immediately before the call to memset(),
>    but shouldn't that happen before 'nargs' is used as an input to
>    copy_from_user()?

I think the reasoning is that there's no way to exploit an out of bounds
value using copy_from_user(). But it's much easier to reason about if we
just do the sanitisation up front.

> 2. If 'nargs' needs this treatment, then why wouldn't the user-supplied
>    'nret' and 'token' need them as well? 'nret' is used to index the
>    same array as 'nargs'. And at least conceptually, 'token' is used to
>    index a data structure (xarray) with array-like semantics (to be
>    fair, this is a relatively recent development and was not the case
>    when this change was submitted).
    
I don't know exactly what smatch looks for when trying to detect these,
but I suspect it's a plain array access. Not sure why it doesn't
complain about nret, but I think it would be good to sanitise it as well.

token is different, at least in the above code, because it's not bounds
checked, so there's no bounds check to bypass. Though maybe there is one
inside the rtas lookup code that should be masked.

cheers

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall
  2024-05-21  1:23         ` Michael Ellerman
@ 2024-05-31  0:35           ` Nathan Lynch
  0 siblings, 0 replies; 8+ messages in thread
From: Nathan Lynch @ 2024-05-31  0:35 UTC (permalink / raw
  To: Michael Ellerman, Breno Leitao, Christophe Leroy
  Cc: linuxppc-dev@lists.ozlabs.org

Michael Ellerman <mpe@ellerman.id.au> writes:
> Nathan Lynch <nathanl@linux.ibm.com> writes:
>>
>> 1. The patch sanitizes 'nargs' immediately before the call to memset(),
>>    but shouldn't that happen before 'nargs' is used as an input to
>>    copy_from_user()?
>
> I think the reasoning is that there's no way to exploit an out of bounds
> value using copy_from_user(). But it's much easier to reason about if we
> just do the sanitisation up front.
>
>> 2. If 'nargs' needs this treatment, then why wouldn't the user-supplied
>>    'nret' and 'token' need them as well? 'nret' is used to index the
>>    same array as 'nargs'. And at least conceptually, 'token' is used to
>>    index a data structure (xarray) with array-like semantics (to be
>>    fair, this is a relatively recent development and was not the case
>>    when this change was submitted).
>     
> I don't know exactly what smatch looks for when trying to detect these,
> but I suspect it's a plain array access. Not sure why it doesn't
> complain about nret, but I think it would be good to sanitise it as
> well.

Agreed. I'm sending a new patch that does this.

> token is different, at least in the above code, because it's not bounds
> checked, so there's no bounds check to bypass.

Right.

> Though maybe there is one inside the rtas lookup code that should be
> masked.

In rtas_function_token()? I think it's OK... the handles passed to it
are always build-time constants that are supposed to be within the
bounds of the function table.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2024-05-31  0:36 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-08-21 18:42 [PATCH] powerpc/kernel: Fix potential spectre v1 in syscall Breno Leitao
2024-03-12  8:17 ` Christophe Leroy
2024-03-12  9:05   ` Breno Leitao
2024-03-12 11:07     ` Michael Ellerman
2024-03-12 13:10       ` Breno Leitao
2024-03-18 15:25       ` Nathan Lynch
2024-05-21  1:23         ` Michael Ellerman
2024-05-31  0:35           ` Nathan Lynch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).