Commit e4140819 authored by Vineet Gupta's avatar Vineet Gupta

ARC: signal handling robustify

A malicious signal handler / restorer can DOS the system by fudging the
user regs saved on stack, causing weird things such as sigreturn returning
to user mode PC but cpu state still being kernel mode....

Ensure that in sigreturn path status32 always has U bit; any other bogosity
(gargbage PC etc) will be taken care of by normal user mode exceptions mechanisms.

Reproducer signal handler:

    void handle_sig(int signo, siginfo_t *info, void *context)
    {
	ucontext_t *uc = context;
	struct user_regs_struct *regs = &(uc->uc_mcontext.regs);

	regs->scratch.status32 = 0;
    }

Before the fix, kernel would go off to weeds like below:

    --------->8-----------
    [ARCLinux]$ ./signal-test
    Path: /signal-test
    CPU: 0 PID: 61 Comm: signal-test Not tainted 4.0.0-rc5+ #65
    task: 8f177880 ti: 5ffe6000 task.ti: 8f15c000

    [ECR   ]: 0x00220200 => Invalid Write @ 0x00000010 by insn @ 0x00010698
    [EFA   ]: 0x00000010
    [BLINK ]: 0x2007c1ee
    [ERET  ]: 0x10698
    [STAT32]: 0x00000000 :                                   <--------
    BTA: 0x00010680	 SP: 0x5ffe7e48	 FP: 0x00000000
    LPS: 0x20003c6c	LPE: 0x20003c70	LPC: 0x00000000
    ...
    --------->8-----------
Reported-by: default avatarAlexey Brodkin <abrodkin@synopsys.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarVineet Gupta <vgupta@synopsys.com>
parent 6914e1e3
...@@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn) ...@@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn)
/* Don't restart from sigreturn */ /* Don't restart from sigreturn */
syscall_wont_restart(regs); syscall_wont_restart(regs);
/*
* Ensure that sigreturn always returns to user mode (in case the
* regs saved on user stack got fudged between save and sigreturn)
* Otherwise it is easy to panic the kernel with a custom
* signal handler and/or restorer which clobberes the status32/ret
* to return to a bogus location in kernel mode.
*/
regs->status32 |= STATUS_U_MASK;
return regs->r0; return regs->r0;
badframe: badframe:
...@@ -229,8 +238,11 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) ...@@ -229,8 +238,11 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
/* /*
* handler returns using sigreturn stub provided already by userpsace * handler returns using sigreturn stub provided already by userpsace
* If not, nuke the process right away
*/ */
BUG_ON(!(ksig->ka.sa.sa_flags & SA_RESTORER)); if(!(ksig->ka.sa.sa_flags & SA_RESTORER))
return 1;
regs->blink = (unsigned long)ksig->ka.sa.sa_restorer; regs->blink = (unsigned long)ksig->ka.sa.sa_restorer;
/* User Stack for signal handler will be above the frame just carved */ /* User Stack for signal handler will be above the frame just carved */
...@@ -296,12 +308,12 @@ static void ...@@ -296,12 +308,12 @@ static void
handle_signal(struct ksignal *ksig, struct pt_regs *regs) handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{ {
sigset_t *oldset = sigmask_to_save(); sigset_t *oldset = sigmask_to_save();
int ret; int failed;
/* Set up the stack frame */ /* Set up the stack frame */
ret = setup_rt_frame(ksig, oldset, regs); failed = setup_rt_frame(ksig, oldset, regs);
signal_setup_done(ret, ksig, 0); signal_setup_done(failed, ksig, 0);
} }
void do_signal(struct pt_regs *regs) void do_signal(struct pt_regs *regs)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment