Re: [PATCH] ARC: uaccess: get_user to zero out dest in cause of fault

From: Linus Torvalds
Date: Sun Aug 21 2016 - 13:52:50 EST


On Sat, Aug 20, 2016 at 11:42 PM, Al Viro <viro@xxxxxxxxxxxxxxxxxx> wrote:
>
> It's not exactly setjmp/longjmp; what I had in mind was along the lines of

That ends up having all the exact same issues as setjmp, and generally
you *do* want the compiler to know about it.

For example, let's say that you have something like

if (start())
return -EFAULT;

... do things that can fault and trigger an exception ..

stop();
return 0;

then it doesn't matter that "start" clobbers all memory and registers,
if it returns twice the code generation by a compiler that doesn't
know about the magical setjmp-like behavior can trigger bugs.

For example, the most common case is that lots of compilers try to
share the final return-point - sometimes because of instrumentation,
sometimes just because there's a big stack frame and the return is a
lot of pop instructions and stack undo code.

And *particularly* if your magical 'start()' function has an inline
asm that clobbers memory and registers, the compiler will have to
spill state to stack around it - but part of the spill might be the
return value that it had in a register.

So the compiler might end up generating code like this:

movl $-EFAULT,8(%rbp) # retval
call start
testl %eax,%eax
jne return_point;

...

movl $0,8(%rbp) # retval

....

return_point:
.. pop-pop-pop-whatever ..
movl 4(%rbp),%eax
.. more stack frame cleanup ..
ret

and notice how if "start()" returns a second time - even if it
restored all registers including the stack pointer - the function
might return the wrong error value if the exception that caused
longjmp happened after the code that had updated the return.

There are lots of other ways a setjmp() point is special. Some
compilers might push/pop values just temporarily around a call, so you
might have sequences like

pushq %rdx
call fn
popq %rdx

where the compiler wanted to save register %rdx around the call (I've
never actually seen gcc generate that code, the exact same thing may
happen with just random register spills).

Again, that fails completely in the presence of a function that
returns twice - even it the stack pointer itself gets reset, the stack
*contents* that the code pops the saved value of %rdx might have been
re-used for something else (and for a register spill, the frame slot
might have been re-used). So now you're restoring garbage.

So the interface you propose is in fact *exactly* the same as setjmp,
and we'd need to make sure that the compiler knows that.

Linus