mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 01:22:07 +00:00
ARC: SA_SIGINFO ucontext regs off-by-one
The regfile provided to SA_SIGINFO signal handler as ucontext was off by one due to pt_regs gutter cleanups in 2013. Before handling signal, user pt_regs are copied onto user_regs_struct and copied back later. Both structs are binary compatible. This was all fine until commit2fa919045b
(ARC: pt_regs update #2) which removed the empty stack slot at top of pt_regs (corresponding to first pad) and made the corresponding fixup in struct user_regs_struct (the pad in there was moved out of @scratch - not removed altogether as it is part of ptrace ABI) struct user_regs_struct { + long pad; struct { - long pad; long bta, lp_start, lp_end,.... } scratch; ... } This meant that now user_regs_struct was off by 1 reg w.r.t pt_regs and signal code needs to user_regs_struct.scratch to reflect it as pt_regs, which is what this commit does. This problem was hidden for 2 years, because both save/restore, despite using wrong location, were using the same location. Only an interim inspection (reproducer below) exposed the issue. void handle_segv(int signo, siginfo_t *info, void *context) { ucontext_t *uc = context; struct user_regs_struct *regs = &(uc->uc_mcontext.regs); printf("regs %x %x\n", <=== prints 7 8 (vs. 8 9) regs->scratch.r8, regs->scratch.r9); } int main() { struct sigaction sa; sa.sa_sigaction = handle_segv; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); sigaction(SIGSEGV, &sa, NULL); asm volatile( "mov r7, 7 \n" "mov r8, 8 \n" "mov r9, 9 \n" "mov r10, 10 \n" :::"r7","r8","r9","r10"); *((unsigned int*)0x10) = 0; } Fixes:2fa919045b
"ARC: pt_regs update #2: Remove unused gutter at start of pt_regs" CC: <stable@vger.kernel.org> Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
This commit is contained in:
parent
bc465aa9d0
commit
6914e1e3f6
@ -67,7 +67,7 @@ stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs,
|
|||||||
sigset_t *set)
|
sigset_t *set)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
err = __copy_to_user(&(sf->uc.uc_mcontext.regs), regs,
|
err = __copy_to_user(&(sf->uc.uc_mcontext.regs.scratch), regs,
|
||||||
sizeof(sf->uc.uc_mcontext.regs.scratch));
|
sizeof(sf->uc.uc_mcontext.regs.scratch));
|
||||||
err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t));
|
err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t));
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)
|
|||||||
if (!err)
|
if (!err)
|
||||||
set_current_blocked(&set);
|
set_current_blocked(&set);
|
||||||
|
|
||||||
err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs),
|
err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs.scratch),
|
||||||
sizeof(sf->uc.uc_mcontext.regs.scratch));
|
sizeof(sf->uc.uc_mcontext.regs.scratch));
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
Loading…
Reference in New Issue
Block a user