powerpc: signals: Stop using current in signal code
Much of the signal code takes a pt_regs on which it operates. Over time the signal code has needed to know more about the thread than what pt_regs can supply, this information is obtained as needed by using 'current'. This approach is not strictly incorrect however it does mean that there is now a hard requirement that the pt_regs being passed around does belong to current, this is never checked. A safer approach is for the majority of the signal functions to take a task_struct from which they can obtain pt_regs and any other information they need. The caveat that the task_struct they are passed must be current doesn't go away but can more easily be checked for. Functions called from outside powerpc signal code are passed a pt_regs and they can confirm that the pt_regs is that of current and pass current to other functions, furthurmore, powerpc signal functions can check that the task_struct they are passed is the same as current avoiding possible corruption of current (or the task they are passed) if this assertion ever fails. CC: paulus@samba.org Signed-off-by: Cyril Bur <cyrilbur@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Цей коміт міститься в:

зафіксовано
Michael Ellerman

джерело
e909fb83d3
коміт
d11994314b
@@ -99,22 +99,24 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
|
||||
}
|
||||
}
|
||||
|
||||
static void do_signal(struct pt_regs *regs)
|
||||
static void do_signal(struct task_struct *tsk)
|
||||
{
|
||||
sigset_t *oldset = sigmask_to_save();
|
||||
struct ksignal ksig;
|
||||
int ret;
|
||||
int is32 = is_32bit_task();
|
||||
|
||||
BUG_ON(tsk != current);
|
||||
|
||||
get_signal(&ksig);
|
||||
|
||||
/* Is there any syscall restart business here ? */
|
||||
check_syscall_restart(regs, &ksig.ka, ksig.sig > 0);
|
||||
check_syscall_restart(tsk->thread.regs, &ksig.ka, ksig.sig > 0);
|
||||
|
||||
if (ksig.sig <= 0) {
|
||||
/* No signal to deliver -- put the saved sigmask back */
|
||||
restore_saved_sigmask();
|
||||
regs->trap = 0;
|
||||
tsk->thread.regs->trap = 0;
|
||||
return; /* no signals delivered */
|
||||
}
|
||||
|
||||
@@ -124,23 +126,22 @@ static void do_signal(struct pt_regs *regs)
|
||||
* user space. The DABR will have been cleared if it
|
||||
* triggered inside the kernel.
|
||||
*/
|
||||
if (current->thread.hw_brk.address &&
|
||||
current->thread.hw_brk.type)
|
||||
__set_breakpoint(¤t->thread.hw_brk);
|
||||
if (tsk->thread.hw_brk.address && tsk->thread.hw_brk.type)
|
||||
__set_breakpoint(&tsk->thread.hw_brk);
|
||||
#endif
|
||||
/* Re-enable the breakpoints for the signal stack */
|
||||
thread_change_pc(current, regs);
|
||||
thread_change_pc(tsk, tsk->thread.regs);
|
||||
|
||||
if (is32) {
|
||||
if (ksig.ka.sa.sa_flags & SA_SIGINFO)
|
||||
ret = handle_rt_signal32(&ksig, oldset, regs);
|
||||
ret = handle_rt_signal32(&ksig, oldset, tsk);
|
||||
else
|
||||
ret = handle_signal32(&ksig, oldset, regs);
|
||||
ret = handle_signal32(&ksig, oldset, tsk);
|
||||
} else {
|
||||
ret = handle_rt_signal64(&ksig, oldset, regs);
|
||||
ret = handle_rt_signal64(&ksig, oldset, tsk);
|
||||
}
|
||||
|
||||
regs->trap = 0;
|
||||
tsk->thread.regs->trap = 0;
|
||||
signal_setup_done(ret, &ksig, test_thread_flag(TIF_SINGLESTEP));
|
||||
}
|
||||
|
||||
@@ -151,8 +152,10 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
|
||||
if (thread_info_flags & _TIF_UPROBE)
|
||||
uprobe_notify_resume(regs);
|
||||
|
||||
if (thread_info_flags & _TIF_SIGPENDING)
|
||||
do_signal(regs);
|
||||
if (thread_info_flags & _TIF_SIGPENDING) {
|
||||
BUG_ON(regs != current->thread.regs);
|
||||
do_signal(current);
|
||||
}
|
||||
|
||||
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
|
||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||
@@ -162,7 +165,7 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
|
||||
user_enter();
|
||||
}
|
||||
|
||||
unsigned long get_tm_stackpointer(struct pt_regs *regs)
|
||||
unsigned long get_tm_stackpointer(struct task_struct *tsk)
|
||||
{
|
||||
/* When in an active transaction that takes a signal, we need to be
|
||||
* careful with the stack. It's possible that the stack has moved back
|
||||
@@ -187,11 +190,13 @@ unsigned long get_tm_stackpointer(struct pt_regs *regs)
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
||||
if (MSR_TM_ACTIVE(regs->msr)) {
|
||||
BUG_ON(tsk != current);
|
||||
|
||||
if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
|
||||
tm_reclaim_current(TM_CAUSE_SIGNAL);
|
||||
if (MSR_TM_TRANSACTIONAL(regs->msr))
|
||||
return current->thread.ckpt_regs.gpr[1];
|
||||
if (MSR_TM_TRANSACTIONAL(tsk->thread.regs->msr))
|
||||
return tsk->thread.ckpt_regs.gpr[1];
|
||||
}
|
||||
#endif
|
||||
return regs->gpr[1];
|
||||
return tsk->thread.regs->gpr[1];
|
||||
}
|
||||
|
Посилання в новій задачі
Заблокувати користувача