Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-17 Thread Oleg Nesterov
On 11/16, Thomas Gleixner wrote:
>
> Subject: x86/dumpstack: Don't try to access user space code of other tasks
> From: Thomas Gleixner 
> Date: Mon, 16 Nov 2020 22:26:52 +0100
> 
> sysrq-t ends up invoking show_opcodes() for each task which tries to access
> the user space code of other processes which is obviously bogus.
> 
> It either manages to dump where the foreign tasks regs->ip points to in
> currents mapping or triggers a pagefault and prints "Code: Bad RIP
> value.". Both is just wrong.
> 
> Add a safeguard in copy_code() and check whether the @regs pointer matches
> currents pt_regs. If not, do not even try to access it.
> 
> While at it, add commentry why using copy_from_user_nmi() is safe in
> copy_code() even if the function name suggests otherwise.
> 
> Reported-by: Mark Mossberg 
> Signed-off-by: Thomas Gleixner 

Acked-by: Oleg Nesterov 



Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-17 Thread Borislav Petkov
On Mon, Nov 16, 2020 at 11:01:03PM +0100, Thomas Gleixner wrote:
> Subject: x86/dumpstack: Don't try to access user space code of other tasks
> From: Thomas Gleixner 
> Date: Mon, 16 Nov 2020 22:26:52 +0100
> 
> sysrq-t ends up invoking show_opcodes() for each task which tries to access
> the user space code of other processes which is obviously bogus.
> 
> It either manages to dump where the foreign tasks regs->ip points to in

I guess you mean here "points to valid mapping of current" or so.

> currents mapping or triggers a pagefault and prints "Code: Bad RIP
> value.". Both is just wrong.
> 
> Add a safeguard in copy_code() and check whether the @regs pointer matches
> currents pt_regs. If not, do not even try to access it.
> 
> While at it, add commentry why using copy_from_user_nmi() is safe in

s/commentry/commentary/

> copy_code() even if the function name suggests otherwise.
> 
> Reported-by: Mark Mossberg 

This is Reported-by: Oleg

> Signed-off-by: Thomas Gleixner 
> ---
>  arch/x86/kernel/dumpstack.c |   23 +++
>  1 file changed, 19 insertions(+), 4 deletions(-)
> 
> --- a/arch/x86/kernel/dumpstack.c
> +++ b/arch/x86/kernel/dumpstack.c
> @@ -78,6 +78,9 @@ static int copy_code(struct pt_regs *reg
>   if (!user_mode(regs))
>   return copy_from_kernel_nofault(buf, (u8 *)src, nbytes);
>  
> + /* The user space code from other tasks cannot be accessed. */
> + if (regs != task_pt_regs(current))
> + return -EPERM;
>   /*
>* Make sure userspace isn't trying to trick us into dumping kernel
>* memory by pointing the userspace instruction pointer at it.
> @@ -85,6 +88,12 @@ static int copy_code(struct pt_regs *reg
>   if (__chk_range_not_ok(src, nbytes, TASK_SIZE_MAX))
>   return -EINVAL;
>  
> + /*
> +  * Even if named copy_from_user_nmi() this can be invoked from
> +  * other contexts and will not try to resolve a pagefault, which is
> +  * the correct thing to do here as this code can be called from any
> +  * context.
> +  */

Can we stick the first part of this comment about "this can be invoked
from other contexts" over the function definition?

>   return copy_from_user_nmi(buf, (void __user *)src, nbytes);
>  }

...

With this, I see Code: only once with Sysrq-T:

[   25.491878] task:bashstate:R  running task stack:0 pid: 
4267 ppid:  4187 flags:0x4000

...

[   25.497740] Code: 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 
00 00 00 48 8d 05 f9 61 0d 00 8b 00 85 c0 75 13 b8 01 00 00 00 0f 05 <48> 3d 00 
f0 ff ff 77 54 c3 0f 1f 00 41 54 49 89 d4 55 48 89 f5 53

which is the shell doing the

$ echo t > /proc/sysrq-trigger

So

Reviewed-by: Borislav Petkov 
Tested-by: Borislav Petkov 

Thanks!

-- 
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette


Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-16 Thread Andy Lutomirski
On Mon, Nov 16, 2020 at 3:37 PM Thomas Gleixner  wrote:
>
> On Mon, Nov 16 2020 at 15:04, Andy Lutomirski wrote:
>
> > On Mon, Nov 16, 2020 at 2:01 PM Thomas Gleixner  wrote:
> >>  arch/x86/kernel/dumpstack.c |   23 +++
> >>  1 file changed, 19 insertions(+), 4 deletions(-)
> >>
> >> --- a/arch/x86/kernel/dumpstack.c
> >> +++ b/arch/x86/kernel/dumpstack.c
> >> @@ -78,6 +78,9 @@ static int copy_code(struct pt_regs *reg
> >> if (!user_mode(regs))
> >> return copy_from_kernel_nofault(buf, (u8 *)src, nbytes);
> >>
> >> +   /* The user space code from other tasks cannot be accessed. */
> >> +   if (regs != task_pt_regs(current))
> >> +   return -EPERM;
> >
> > Depending on exactly where this gets called, this may not be
> > sufficient.  You should also check nmi_uaccess_okay().
>
> which is what copy_from_user_nmi() already does.

Whoops.  I thought I checked that...


Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-16 Thread Thomas Gleixner
On Mon, Nov 16 2020 at 15:04, Andy Lutomirski wrote:

> On Mon, Nov 16, 2020 at 2:01 PM Thomas Gleixner  wrote:
>>  arch/x86/kernel/dumpstack.c |   23 +++
>>  1 file changed, 19 insertions(+), 4 deletions(-)
>>
>> --- a/arch/x86/kernel/dumpstack.c
>> +++ b/arch/x86/kernel/dumpstack.c
>> @@ -78,6 +78,9 @@ static int copy_code(struct pt_regs *reg
>> if (!user_mode(regs))
>> return copy_from_kernel_nofault(buf, (u8 *)src, nbytes);
>>
>> +   /* The user space code from other tasks cannot be accessed. */
>> +   if (regs != task_pt_regs(current))
>> +   return -EPERM;
>
> Depending on exactly where this gets called, this may not be
> sufficient.  You should also check nmi_uaccess_okay().

which is what copy_from_user_nmi() already does.


Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-16 Thread Andy Lutomirski
On Mon, Nov 16, 2020 at 2:01 PM Thomas Gleixner  wrote:
>  arch/x86/kernel/dumpstack.c |   23 +++
>  1 file changed, 19 insertions(+), 4 deletions(-)
>
> --- a/arch/x86/kernel/dumpstack.c
> +++ b/arch/x86/kernel/dumpstack.c
> @@ -78,6 +78,9 @@ static int copy_code(struct pt_regs *reg
> if (!user_mode(regs))
> return copy_from_kernel_nofault(buf, (u8 *)src, nbytes);
>
> +   /* The user space code from other tasks cannot be accessed. */
> +   if (regs != task_pt_regs(current))
> +   return -EPERM;

Depending on exactly where this gets called, this may not be
sufficient.  You should also check nmi_uaccess_okay().

--Andy


Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-16 Thread Thomas Gleixner
On Tue, Nov 03 2020 at 19:20, Borislav Petkov wrote:
> On Tue, Nov 03, 2020 at 07:11:15PM +0100, Oleg Nesterov wrote:
>> > I'm thinking copy_code() should not use copy_from_user_nmi() if former
>> > can be called in non-atomic context too.

While copy_from_user_nmi() is named that way, it can be invoked from
other contexts as well. See the comment inside.

>> I understand, but why do you think this makes sense?
>
> Because the copy_from_user_nmi()'s name tells me that it is at least
> supposed to be called in atomic context. At least this is how I
> understand it. And in atomic context regs is supposed to belong to
> current, right?

Whatever context you are in current can only read it's own user space
obviously.

AFAICT even before the change I did, show_opcodes() did not care and
just either dumped what was available at regs->ip in the current tasks
user space mapping or faulted.

Fix below.

Thanks,

tglx
---
Subject: x86/dumpstack: Don't try to access user space code of other tasks
From: Thomas Gleixner 
Date: Mon, 16 Nov 2020 22:26:52 +0100

sysrq-t ends up invoking show_opcodes() for each task which tries to access
the user space code of other processes which is obviously bogus.

It either manages to dump where the foreign tasks regs->ip points to in
currents mapping or triggers a pagefault and prints "Code: Bad RIP
value.". Both is just wrong.

Add a safeguard in copy_code() and check whether the @regs pointer matches
currents pt_regs. If not, do not even try to access it.

While at it, add commentry why using copy_from_user_nmi() is safe in
copy_code() even if the function name suggests otherwise.

Reported-by: Mark Mossberg 
Signed-off-by: Thomas Gleixner 
---
 arch/x86/kernel/dumpstack.c |   23 +++
 1 file changed, 19 insertions(+), 4 deletions(-)

--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -78,6 +78,9 @@ static int copy_code(struct pt_regs *reg
if (!user_mode(regs))
return copy_from_kernel_nofault(buf, (u8 *)src, nbytes);
 
+   /* The user space code from other tasks cannot be accessed. */
+   if (regs != task_pt_regs(current))
+   return -EPERM;
/*
 * Make sure userspace isn't trying to trick us into dumping kernel
 * memory by pointing the userspace instruction pointer at it.
@@ -85,6 +88,12 @@ static int copy_code(struct pt_regs *reg
if (__chk_range_not_ok(src, nbytes, TASK_SIZE_MAX))
return -EINVAL;
 
+   /*
+* Even if named copy_from_user_nmi() this can be invoked from
+* other contexts and will not try to resolve a pagefault, which is
+* the correct thing to do here as this code can be called from any
+* context.
+*/
return copy_from_user_nmi(buf, (void __user *)src, nbytes);
 }
 
@@ -115,13 +124,19 @@ void show_opcodes(struct pt_regs *regs,
u8 opcodes[OPCODE_BUFSIZE];
unsigned long prologue = regs->ip - PROLOGUE_SIZE;
 
-   if (copy_code(regs, opcodes, prologue, sizeof(opcodes))) {
-   printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n",
-  loglvl, prologue);
-   } else {
+   switch (copy_code(regs, opcodes, prologue, sizeof(opcodes))) {
+   case 0:
printk("%sCode: %" __stringify(PROLOGUE_SIZE) "ph <%02x> %"
   __stringify(EPILOGUE_SIZE) "ph\n", loglvl, opcodes,
   opcodes[PROLOGUE_SIZE], opcodes + PROLOGUE_SIZE + 1);
+   break;
+   case -EPERM:
+   /* No access to the user space stack of other tasks. Ignore. */
+   break;
+   default:
+   printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n",
+  loglvl, prologue);
+   break;
}
 }
 


Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-03 Thread Borislav Petkov
On Tue, Nov 03, 2020 at 07:11:15PM +0100, Oleg Nesterov wrote:
> > I'm thinking copy_code() should not use copy_from_user_nmi() if former
> > can be called in non-atomic context too.
> 
> I understand, but why do you think this makes sense?

Because the copy_from_user_nmi()'s name tells me that it is at least
supposed to be called in atomic context. At least this is how I
understand it. And in atomic context regs is supposed to belong to
current, right?

So I kinda agree with what you're proposing but if copy_from_user_nmi()
can be "tricked" into reading off from the weeds, then there should be
a big fat warning above it at least so that users are warned to do the
appropriate checks.

Or there should be another wrapper around it which does the
regs-belongs-to-current checks, etc and copy_code() should use that
wrapper...

AFAICT at least.

-- 
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette


Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-03 Thread Oleg Nesterov
On 11/03, Borislav Petkov wrote:
>
> On Tue, Nov 03, 2020 at 06:47:44PM +0100, Oleg Nesterov wrote:
> > > I'm thinking this should not use the atomic variant if it can get called
> > > in !atomic context too.
> >
> > For what?
>
> I'm thinking copy_code() should not use copy_from_user_nmi() if former
> can be called in non-atomic context too.

I understand, but why do you think this makes sense?

Say, do you think it is fine to block in fuse_readpage() ?

Anyway, this is off-topic and I won't argue.

Oleg.



Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-03 Thread Borislav Petkov
On Tue, Nov 03, 2020 at 06:47:44PM +0100, Oleg Nesterov wrote:
> > I'm thinking this should not use the atomic variant if it can get called
> > in !atomic context too.
> 
> For what?

I'm thinking copy_code() should not use copy_from_user_nmi() if former
can be called in non-atomic context too.

-- 
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette


Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-03 Thread Oleg Nesterov
On 11/03, Borislav Petkov wrote:
>
> On Tue, Nov 03, 2020 at 01:50:34PM +0100, Oleg Nesterov wrote:
> > Another problem is that show_opcodes() makes no sense if user_mode(regs)
> > and tsk is not current.
>
> Because if not current, we would access *some* user address space but
> not the one to which regs belong to?

Yes, because if not current, copy_from_user() will access the current's
user address space at address = foreign process's regs->ip.

> > Try "echo t > /proc/sysrq-trigger".
>
> What am I looking for?
>
> I see a bunch of:
>
> [   37.622896] Code: Unable to access opcode bytes at RIP 

this means that foreign_regs->ip is not mmapped,

> and three Code: lines with opcode bytes, as expected:
>
> [   37.148693] Code: 11 0d 00 48 89 c6 4c 89 ef e8 98 07 00 00 48 83 f8 ff 0f 
> 84 3e 02 00 00 48 3b 05 b7 28 0d 00 48 89 c3 0f 83 b5 00 00 00 48 8b <0d> e7 
> 10 0d 00 48 83 f8 0d 76 13 48 b8 28 75 6e 72 65 61 63 68 48

I'd say this is NOT expected and adds the unnecessary confusion.
./scripts/decodecode reports

...

Code starting with the faulting instruction
===
   0:   0d e7 10 0d 00  or $0xd10e7,%eax
   5:   48 83 f8 0d cmp$0xd,%rax
   9:   76 13   jbe0x1e
   b:   48 b8 28 75 6e 72 65movabs $0x68636165726e7528,%rax
  12:   61 63 68
  15:   48  rex.W

and this is because foreign_regs->ip happens to be a valid address in 
current->mm.

> I'm thinking this should not use the atomic variant if it can get called
> in !atomic context too.

For what?

Oleg.



Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-03 Thread Borislav Petkov
On Tue, Nov 03, 2020 at 01:50:34PM +0100, Oleg Nesterov wrote:
> Another problem is that show_opcodes() makes no sense if user_mode(regs)
> and tsk is not current.

Because if not current, we would access *some* user address space but
not the one to which regs belong to?

> Try "echo t > /proc/sysrq-trigger".

What am I looking for?

I see a bunch of:

[   37.622896] Code: Unable to access opcode bytes at RIP 

and three Code: lines with opcode bytes, as expected:

[   37.148693] Code: 11 0d 00 48 89 c6 4c 89 ef e8 98 07 00 00 48 83 f8 ff 0f 
84 3e 02 00 00 48 3b 05 b7 28 0d 00 48 89 c3 0f 83 b5 00 00 00 48 8b <0d> e7 10 
0d 00 48 83 f8 0d 76 13 48 b8 28 75 6e 72 65 61 63 68 48

So all those other but the three cases, copy_code() failed.

> In this case copy_from_user_nmi() will either fail, or (worse) it will
> read the "random" memory from current->mm.
> 
> Perhaps we can add something like
> 
>   if (user_mode(regs) && regs != task_pt_regs(current))
>   return;
> 
> at the start of show_opcodes() ?

tglx made it use copy_from_user_nmi() in:

d181d2da0141 ("x86/dumpstack: Dump user space code correctly again")

I'm thinking this should not use the atomic variant if it can get called
in !atomic context too.

Thomas?

Leaving in the rest for reference.

> > --- a/arch/x86/kernel/dumpstack.c
> > +++ b/arch/x86/kernel/dumpstack.c
> > @@ -115,7 +115,8 @@ void show_opcodes(struct pt_regs *regs, const char 
> > *loglvl)
> > unsigned long prologue = regs->ip - PROLOGUE_SIZE;
> >  
> > if (copy_code(regs, opcodes, prologue, sizeof(opcodes))) {
> > -   printk("%sCode: Bad RIP value.\n", loglvl);
> > +   printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n",
> > +  loglvl, prologue);
> > } else {
> > printk("%sCode: %" __stringify(PROLOGUE_SIZE) "ph <%02x> %"
> >__stringify(EPILOGUE_SIZE) "ph\n", loglvl, opcodes,
> > -- 
> > 2.25.1

-- 
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette


Re: [PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-11-03 Thread Oleg Nesterov
On 10/02, Mark Mossberg wrote:
>
> Printing "Bad RIP value" if copy_code() fails can be misleading for
> userspace pointers, since copy_code() can fail if the instruction
> pointer is valid, but the code is paged out.

Another problem is that show_opcodes() makes no sense if user_mode(regs)
and tsk is not current. Try "echo t > /proc/sysrq-trigger".

In this case copy_from_user_nmi() will either fail, or (worse) it will
read the "random" memory from current->mm.

Perhaps we can add something like

if (user_mode(regs) && regs != task_pt_regs(current))
return;

at the start of show_opcodes() ?

> --- a/arch/x86/kernel/dumpstack.c
> +++ b/arch/x86/kernel/dumpstack.c
> @@ -115,7 +115,8 @@ void show_opcodes(struct pt_regs *regs, const char 
> *loglvl)
>   unsigned long prologue = regs->ip - PROLOGUE_SIZE;
>  
>   if (copy_code(regs, opcodes, prologue, sizeof(opcodes))) {
> - printk("%sCode: Bad RIP value.\n", loglvl);
> + printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n",
> +loglvl, prologue);
>   } else {
>   printk("%sCode: %" __stringify(PROLOGUE_SIZE) "ph <%02x> %"
>  __stringify(EPILOGUE_SIZE) "ph\n", loglvl, opcodes,
> -- 
> 2.25.1
> 



[PATCH v2] x86/dumpstack: Fix misleading instruction pointer error message

2020-10-01 Thread Mark Mossberg
Printing "Bad RIP value" if copy_code() fails can be misleading for
userspace pointers, since copy_code() can fail if the instruction
pointer is valid, but the code is paged out. This is because copy_code()
calls copy_from_user_nmi() for userspace pointers, which disables page
fault handling.

This is reproducible in OOM situations, where it's plausible that the
code may be reclaimed in the time between entry into the kernel and when
this message is printed. This leaves a misleading log in dmesg that
suggests instruction pointer corruption has occurred, which may alarm
users.

This patch changes the message to state the error condition more
precisely.

Thanks to Jann Horn for help with understanding OOM reclamation.

Signed-off-by: Mark Mossberg 
---
 arch/x86/kernel/dumpstack.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 48ce44576947..ea8d51ec251b 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -115,7 +115,8 @@ void show_opcodes(struct pt_regs *regs, const char *loglvl)
unsigned long prologue = regs->ip - PROLOGUE_SIZE;
 
if (copy_code(regs, opcodes, prologue, sizeof(opcodes))) {
-   printk("%sCode: Bad RIP value.\n", loglvl);
+   printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n",
+  loglvl, prologue);
} else {
printk("%sCode: %" __stringify(PROLOGUE_SIZE) "ph <%02x> %"
   __stringify(EPILOGUE_SIZE) "ph\n", loglvl, opcodes,
-- 
2.25.1