From: Nicholas Piggin <npiggin@gmail.com>
To: Christophe Leroy <christophe.leroy@csgroup.eu>,
linuxppc-dev@lists.ozlabs.org,
Michael Ellerman <mpe@ellerman.id.au>
Cc: dja@axtens.net, cmr@codefail.de
Subject: Re: [PATCH] powerpc/signal64: Copy siginfo before changing regs->nip
Date: Tue, 15 Jun 2021 12:11:14 +1000 [thread overview]
Message-ID: <1623722824.bpyc873xto.astroid@bobo.none> (raw)
In-Reply-To: <a7739358-6dd3-2f5d-50c4-f6b908ab2718@csgroup.eu>
Excerpts from Christophe Leroy's message of June 14, 2021 5:22 pm:
>
>
> Le 14/06/2021 à 07:55, Nicholas Piggin a écrit :
>> Excerpts from Christophe Leroy's message of June 14, 2021 3:31 pm:
>>>
>>>
>>> Le 14/06/2021 à 03:29, Nicholas Piggin a écrit :
>>>> Excerpts from Nicholas Piggin's message of June 14, 2021 10:47 am:
>>>>> Excerpts from Michael Ellerman's message of June 8, 2021 11:46 pm:
>>>>>> In commit 96d7a4e06fab ("powerpc/signal64: Rewrite handle_rt_signal64()
>>>>>> to minimise uaccess switches") the 64-bit signal code was rearranged to
>>>>>> use user_write_access_begin/end().
>>>>>>
>>>>>> As part of that change the call to copy_siginfo_to_user() was moved
>>>>>> later in the function, so that it could be done after the
>>>>>> user_write_access_end().
>>>>>>
>>>>>> In particular it was moved after we modify regs->nip to point to the
>>>>>> signal trampoline. That means if copy_siginfo_to_user() fails we exit
>>>>>> handle_rt_signal64() with an error but with regs->nip modified, whereas
>>>>>> previously we would not modify regs->nip until the copy succeeded.
>>>>>>
>>>>>> Returning an error from signal delivery but with regs->nip updated
>>>>>> leaves the process in a sort of half-delivered state. We do immediately
>>>>>> force a SEGV in signal_setup_done(), called from do_signal(), so the
>>>>>> process should never run in the half-delivered state.
>>>>>>
>>>>>> However that SEGV is not delivered until we've gone around to
>>>>>> do_notify_resume() again, so it's possible some tracing could observe
>>>>>> the half-delivered state.
>>>>>>
>>>>>> There are other cases where we fail signal delivery with regs partly
>>>>>> updated, eg. the write to newsp and SA_SIGINFO, but the latter at least
>>>>>> is very unlikely to fail as it reads back from the frame we just wrote
>>>>>> to.
>>>>>>
>>>>>> Looking at other arches they seem to be more careful about leaving regs
>>>>>> unchanged until the copy operations have succeeded, and in general that
>>>>>> seems like good hygenie.
>>>>>>
>>>>>> So although the current behaviour is not cleary buggy, it's also not
>>>>>> clearly correct. So move the call to copy_siginfo_to_user() up prior to
>>>>>> the modification of regs->nip, which is closer to the old behaviour, and
>>>>>> easier to reason about.
>>>>>
>>>>> Good catch, should it still have a Fixes: tag though? Even if it's not
>>>>> clearly buggy we want it to be patched.
>>>>
>>>> Also...
>>>>
>>>>>>
>>>>>> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
>>>>>> ---
>>>>>> arch/powerpc/kernel/signal_64.c | 9 ++++-----
>>>>>> 1 file changed, 4 insertions(+), 5 deletions(-)
>>>>>>
>>>>>> diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
>>>>>> index dca66481d0c2..f9e1f5428b9e 100644
>>>>>> --- a/arch/powerpc/kernel/signal_64.c
>>>>>> +++ b/arch/powerpc/kernel/signal_64.c
>>>>>> @@ -902,6 +902,10 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
>>>>>> unsafe_copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set), badframe_block);
>>>>>> user_write_access_end();
>>>>>>
>>>>>> + /* Save the siginfo outside of the unsafe block. */
>>>>>> + if (copy_siginfo_to_user(&frame->info, &ksig->info))
>>>>>> + goto badframe;
>>>>>> +
>>>>>> /* Make sure signal handler doesn't get spurious FP exceptions */
>>>>>> tsk->thread.fp_state.fpscr = 0;
>>>>>>
>>>>>> @@ -915,11 +919,6 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
>>>>>> regs->nip = (unsigned long) &frame->tramp[0];
>>>>>> }
>>>>>>
>>>>>> -
>>>>>> - /* Save the siginfo outside of the unsafe block. */
>>>>>> - if (copy_siginfo_to_user(&frame->info, &ksig->info))
>>>>>> - goto badframe;
>>>>>> -
>>>>>> /* Allocate a dummy caller frame for the signal handler. */
>>>>>> newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
>>>>>> err |= put_user(regs->gpr[1], (unsigned long __user *)newsp);
>>>>
>>>> Does the same reasoning apply to this one and the ELF V1 function
>>>> descriptor thing? It seems like you could move all of that block
>>>> up instead. With your other SA_SIGINFO get_user patch, there would
>>>> then be no possibility of error after you start modifying regs.
>>>>
>>>
>>> To move the above in the user access block, we need to open a larger window. At the time being the
>>> window opened only contains the 'frame'. 'newsp' points before the 'frame'.
>>>
>>
>> Only by 64/128 bytes though. Is that a problem? Not for 64s. Could it
>> cause more overhead than it saves on other platforms?
>
> No it is not a problem at all, just need to not be forgotten, on ppc64 it may go unnoticed, on 32s
> it will blew up if we forget to enlarge the access window and the access involves a different 256M
> segment (Very unlikely for sure but ...)
Okay, and it's a good point. Would be nice if there was some sanitizer
that could check this to byte granularity.
Thanks,
Nick
>> For protection, it looks like all the important control data is in the
>> signal frame anyway, this frame is just for stack unwinding?
>
> That's my understanding as well.
next prev parent reply other threads:[~2021-06-15 2:11 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-08 13:46 [PATCH] powerpc/signal64: Copy siginfo before changing regs->nip Michael Ellerman
2021-06-14 0:47 ` Nicholas Piggin
2021-06-14 1:29 ` Nicholas Piggin
2021-06-14 5:31 ` Christophe Leroy
2021-06-14 5:55 ` Nicholas Piggin
2021-06-14 7:22 ` Christophe Leroy
2021-06-15 2:11 ` Nicholas Piggin [this message]
2021-06-15 2:07 ` Michael Ellerman
2021-06-15 2:05 ` Michael Ellerman
2021-06-18 3:50 ` Michael Ellerman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1623722824.bpyc873xto.astroid@bobo.none \
--to=npiggin@gmail.com \
--cc=christophe.leroy@csgroup.eu \
--cc=cmr@codefail.de \
--cc=dja@axtens.net \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=mpe@ellerman.id.au \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox