summaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/signal.c')
-rw-r--r--arch/sparc/kernel/signal.c298
1 files changed, 169 insertions, 129 deletions
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 357d30af5..287ed6cdc 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.82 1998/07/31 05:18:51 jj Exp $
+/* $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -75,6 +75,7 @@ struct new_signal_frame {
__siginfo_fpu_t *fpu_save;
unsigned long insns [2] __attribute__ ((aligned (8)));
unsigned int extramask[_NSIG_WORDS - 1];
+ unsigned int extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
@@ -86,6 +87,7 @@ struct rt_signal_frame {
__siginfo_fpu_t *fpu_save;
unsigned int insns [2];
stack_t stack;
+ unsigned int extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
@@ -203,16 +205,19 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
#endif
current->used_math = 1;
current->flags &= ~PF_USEDFPU;
+
+ if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
+ return -EFAULT;
- err = copy_from_user(&current->tss.float_regs[0], &fpu->si_float_regs[0],
- (sizeof(unsigned long) * 32));
+ err = __copy_from_user(&current->tss.float_regs[0], &fpu->si_float_regs[0],
+ (sizeof(unsigned long) * 32));
err |= __get_user(current->tss.fsr, &fpu->si_fsr);
err |= __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
if (current->tss.fpqdepth != 0)
- err |= copy_from_user(&current->tss.fpqueue[0],
- &fpu->si_fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
+ err |= __copy_from_user(&current->tss.fpqueue[0],
+ &fpu->si_fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
return err;
}
@@ -241,7 +246,7 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
/* 2. Restore the state */
up_psr = regs->psr;
- err |= copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
+ err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
/* User can only change condition codes and FPU enabling in %psr. */
regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
@@ -250,14 +255,14 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
- err |= restore_fpu_state(regs, sf->fpu_save);
+ err |= restore_fpu_state(regs, fpu_save);
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
err |= __get_user(set.sig[0], &sf->info.si_mask);
- err |= copy_from_user(&set.sig[1], &sf->extramask,
- (_NSIG_WORDS-1) * sizeof(unsigned int));
+ err |= __copy_from_user(&set.sig[1], &sf->extramask,
+ (_NSIG_WORDS-1) * sizeof(unsigned int));
if (err)
goto segv_and_exit;
@@ -270,8 +275,6 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
return;
segv_and_exit:
- /* Ugh, we need to grab master lock in these rare cases ;-( */
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -305,8 +308,8 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
*/
err |= __get_user(set.sig[0], &scptr->sigc_mask);
/* Note that scptr + 1 points to extramask */
- err |= copy_from_user(&set.sig[1], scptr + 1,
- (_NSIG_WORDS - 1) * sizeof(unsigned int));
+ err |= __copy_from_user(&set.sig[1], scptr + 1,
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
if (err)
goto segv_and_exit;
@@ -352,7 +355,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
(((unsigned long) sf) & 0x03))
goto segv;
- err = get_user(pc, &sf->regs.pc);
+ err = __get_user(pc, &sf->regs.pc);
err |= __get_user(npc, &sf->regs.npc);
err |= ((pc | npc) & 0x03);
@@ -366,8 +369,8 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
err |= __get_user(fpu_save, &sf->fpu_save);
if(fpu_save)
- err |= restore_fpu_state(regs, &sf->fpu_state);
- err |= copy_from_user(&set, &sf->mask, sizeof(sigset_t));
+ err |= restore_fpu_state(regs, fpu_save);
+ err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
@@ -423,7 +426,7 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
{
struct signal_sframe *sframep;
struct sigcontext *sc;
- int window = 0;
+ int window = 0, err;
synchronize_user_stack();
sframep = (struct signal_sframe *)get_sigframe(sa, regs, SF_ALIGNEDSZ);
@@ -443,58 +446,63 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
sc = &sframep->sig_context;
/* We've already made sure frame pointer isn't in kernel space... */
- __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), &sc->sigc_onstack);
- __put_user(oldset->sig[0], &sc->sigc_mask);
- __copy_to_user(sframep->extramask, &oldset->sig[1],
- (_NSIG_WORDS - 1) * sizeof(unsigned int));
- __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
- __put_user(pc, &sc->sigc_pc);
- __put_user(npc, &sc->sigc_npc);
- __put_user(regs->psr, &sc->sigc_psr);
- __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
- __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
- __put_user(current->tss.w_saved, &sc->sigc_oswins);
+ err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK),
+ &sc->sigc_onstack);
+ err |= __put_user(oldset->sig[0], &sc->sigc_mask);
+ err |= __copy_to_user(sframep->extramask, &oldset->sig[1],
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
+ err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
+ err |= __put_user(pc, &sc->sigc_pc);
+ err |= __put_user(npc, &sc->sigc_npc);
+ err |= __put_user(regs->psr, &sc->sigc_psr);
+ err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
+ err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
+ err |= __put_user(current->tss.w_saved, &sc->sigc_oswins);
if(current->tss.w_saved)
for(window = 0; window < current->tss.w_saved; window++) {
sc->sigc_spbuf[window] =
(char *)current->tss.rwbuf_stkptrs[window];
- copy_to_user(&sc->sigc_wbuf[window],
- &current->tss.reg_window[window],
- sizeof(struct reg_window));
+ err |= __copy_to_user(&sc->sigc_wbuf[window],
+ &current->tss.reg_window[window],
+ sizeof(struct reg_window));
}
else
- copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
- sizeof(struct reg_window));
+ err |= __copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
+ sizeof(struct reg_window));
current->tss.w_saved = 0; /* So process is allowed to execute. */
- __put_user(signr, &sframep->sig_num);
+ err |= __put_user(signr, &sframep->sig_num);
if(signr == SIGSEGV ||
signr == SIGILL ||
signr == SIGFPE ||
signr == SIGBUS ||
signr == SIGEMT) {
- __put_user(current->tss.sig_desc, &sframep->sig_code);
- __put_user(current->tss.sig_address, &sframep->sig_address);
+ err |= __put_user(current->tss.sig_desc, &sframep->sig_code);
+ err |= __put_user(current->tss.sig_address, &sframep->sig_address);
} else {
- __put_user(0, &sframep->sig_code);
- __put_user(0, &sframep->sig_address);
+ err |= __put_user(0, &sframep->sig_code);
+ err |= __put_user(0, &sframep->sig_address);
}
- __put_user(sc, &sframep->sig_scptr);
+ err |= __put_user(sc, &sframep->sig_scptr);
+ if (err)
+ goto sigsegv;
+
regs->u_regs[UREG_FP] = (unsigned long) sframep;
regs->pc = (unsigned long) sa->sa_handler;
regs->npc = (regs->pc + 4);
return;
sigill_and_return:
- /* Ugh, we need to grab master lock in these rare cases ;-( */
- lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ do_exit(SIGSEGV);
}
-static inline void
+static inline int
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
+ int err = 0;
#ifdef __SMP__
if (current->flags & PF_USEDFPU) {
put_psr(get_psr() | PSR_EF);
@@ -512,15 +520,16 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
regs->psr &= ~(PSR_EF);
}
#endif
- copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
- (sizeof(unsigned long) * 32));
- __put_user(current->tss.fsr, &fpu->si_fsr);
- __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
+ err |= __copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+ (sizeof(unsigned long) * 32));
+ err |= __put_user(current->tss.fsr, &fpu->si_fsr);
+ err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
if (current->tss.fpqdepth != 0)
- copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
+ err |= __copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
current->used_math = 0;
+ return err;
}
static inline void
@@ -528,7 +537,7 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset)
{
struct new_signal_frame *sf;
- int sigframe_size;
+ int sigframe_size, err;
/* 1. Make sure everything is clean */
synchronize_user_stack();
@@ -551,20 +560,24 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
}
/* 2. Save the current process state */
- copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+ err = __copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+
+ err |= __put_user(0, &sf->extra_size);
if (current->used_math) {
- save_fpu_state(regs, &sf->fpu_state);
- __put_user(&sf->fpu_state, &sf->fpu_save);
+ err |= save_fpu_state(regs, &sf->fpu_state);
+ err |= __put_user(&sf->fpu_state, &sf->fpu_save);
} else {
- __put_user(0, &sf->fpu_save);
+ err |= __put_user(0, &sf->fpu_save);
}
- __put_user(oldset->sig[0], &sf->info.si_mask);
- __copy_to_user(sf->extramask, &oldset->sig[1],
- (_NSIG_WORDS - 1) * sizeof(unsigned int));
- copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
- sizeof (struct reg_window));
+ err |= __put_user(oldset->sig[0], &sf->info.si_mask);
+ err |= __copy_to_user(sf->extramask, &oldset->sig[1],
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
+ err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+ sizeof (struct reg_window));
+ if (err)
+ goto sigsegv;
/* 3. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = (unsigned long) sf;
@@ -581,8 +594,13 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
else {
regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
- __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
- __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+ /* mov __NR_sigreturn, %g1 */
+ err |= __put_user(0x821020d8, &sf->insns[0]);
+
+ /* t 0x10 */
+ err |= __put_user(0x91d02010, &sf->insns[1]);
+ if (err)
+ goto sigsegv;
/* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
@@ -590,8 +608,9 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
return;
sigill_and_return:
- lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ do_exit(SIGSEGV);
}
static inline void
@@ -601,7 +620,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
struct rt_signal_frame *sf;
int sigframe_size;
unsigned int psr;
- int i;
+ int err;
synchronize_user_stack();
sigframe_size = RT_ALIGNEDSZ;
@@ -613,30 +632,33 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
if(current->tss.w_saved != 0)
goto sigill;
- put_user(regs->pc, &sf->regs.pc);
- __put_user(regs->npc, &sf->regs.npc);
- __put_user(regs->y, &sf->regs.y);
+ err = __put_user(regs->pc, &sf->regs.pc);
+ err |= __put_user(regs->npc, &sf->regs.npc);
+ err |= __put_user(regs->y, &sf->regs.y);
psr = regs->psr;
if(current->used_math)
psr |= PSR_EF;
- __put_user(psr, &sf->regs.psr);
- for(i = 0; i < 16; i++)
- __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+ err |= __put_user(psr, &sf->regs.psr);
+ err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
+ err |= __put_user(0, &sf->extra_size);
+
if(psr & PSR_EF) {
- save_fpu_state(regs, &sf->fpu_state);
- __put_user(&sf->fpu_state, &sf->fpu_save);
+ err |= save_fpu_state(regs, &sf->fpu_state);
+ err |= __put_user(&sf->fpu_state, &sf->fpu_save);
} else {
- __put_user(0, &sf->fpu_save);
+ err |= __put_user(0, &sf->fpu_save);
}
- __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
+ err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
/* Setup sigaltstack */
- __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
- __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
- __put_user(current->sas_ss_size, &sf->stack.ss_size);
+ err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
- copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
- sizeof (struct reg_window));
+ err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+ sizeof (struct reg_window));
+ if (err)
+ goto sigsegv;
regs->u_regs[UREG_FP] = (unsigned long) sf;
regs->u_regs[UREG_I0] = signo;
@@ -650,8 +672,13 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
else {
regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
- __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
- __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+ /* mov __NR_sigreturn, %g1 */
+ err |= __put_user(0x821020d8, &sf->insns[0]);
+
+ /* t 0x10 */
+ err |= __put_user(0x91d02010, &sf->insns[1]);
+ if (err)
+ goto sigsegv;
/* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
@@ -659,8 +686,9 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
return;
sigill:
- lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ do_exit(SIGSEGV);
}
/* Setup a Solaris stack frame */
@@ -675,7 +703,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
svr4_gwindows_t *gw;
svr4_ucontext_t *uc;
svr4_sigset_t setv;
- int window = 0;
+ int window = 0, err;
synchronize_user_stack();
sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, SVR4_SF_ALIGNED + REGWIN_SZ);
@@ -688,7 +716,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
}
/* Start with a clean frame pointer and fill it */
- clear_user(sfp, sizeof (*sfp));
+ err = __clear_user(sfp, sizeof (*sfp));
/* Setup convenience variables */
si = &sfp->si;
@@ -706,32 +734,32 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
if (_NSIG_WORDS >= 4) {
setv.sigbits[2] = oldset->sig[2];
setv.sigbits[3] = oldset->sig[3];
- __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
} else
- __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
+ err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
/* Store registers */
- __put_user(regs->pc, &((*gr) [SVR4_PC]));
- __put_user(regs->npc, &((*gr) [SVR4_NPC]));
- __put_user(regs->psr, &((*gr) [SVR4_PSR]));
- __put_user(regs->y, &((*gr) [SVR4_Y]));
+ err |= __put_user(regs->pc, &((*gr) [SVR4_PC]));
+ err |= __put_user(regs->npc, &((*gr) [SVR4_NPC]));
+ err |= __put_user(regs->psr, &((*gr) [SVR4_PSR]));
+ err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
/* Copy g [1..7] and o [0..7] registers */
- copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
- copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
+ err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
+ err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
/* Setup sigaltstack */
- __put_user(current->sas_ss_sp, &uc->stack.sp);
- __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
- __put_user(current->sas_ss_size, &uc->stack.size);
+ err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
+ err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+ err |= __put_user(current->sas_ss_size, &uc->stack.size);
/* Save the currently window file: */
/* 1. Link sfp->uc->gwins to our windows */
- __put_user(gw, &mc->gwin);
+ err |= __put_user(gw, &mc->gwin);
/* 2. Number of windows to restore at setcontext (): */
- __put_user(current->tss.w_saved, &gw->count);
+ err |= __put_user(current->tss.w_saved, &gw->count);
/* 3. Save each valid window
* Currently, it makes a copy of the windows from the kernel copy.
@@ -745,9 +773,11 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
* to flush the user windows.
*/
for(window = 0; window < current->tss.w_saved; window++) {
- __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
- copy_to_user(&gw->win [window], &current->tss.reg_window [window], sizeof (svr4_rwindow_t));
- __put_user(0, gw->winptr [window]);
+ err |= __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
+ err |= __copy_to_user(&gw->win [window],
+ &current->tss.reg_window [window],
+ sizeof (svr4_rwindow_t));
+ err |= __put_user(0, gw->winptr [window]);
}
/* 4. We just pay attention to the gw->count field on setcontext */
@@ -758,8 +788,10 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
* that much currently, should use those that David already
* is providing with tss.sig_desc
*/
- __put_user(signr, &si->siginfo.signo);
- __put_user(SVR4_SINOINFO, &si->siginfo.code);
+ err |= __put_user(signr, &si->siginfo.signo);
+ err |= __put_user(SVR4_SINOINFO, &si->siginfo.code);
+ if (err)
+ goto sigsegv;
regs->u_regs[UREG_FP] = (unsigned long) sfp;
regs->pc = (unsigned long) sa->sa_handler;
@@ -772,10 +804,13 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
if (regs->u_regs [14]){
struct reg_window *rw = (struct reg_window *) regs->u_regs [14];
- __put_user(signr, &rw->ins [0]);
- __put_user(si, &rw->ins [1]);
- __put_user(uc, &rw->ins [2]);
- __put_user(sfp, &rw->ins [6]); /* frame pointer */
+ err |= __put_user(signr, &rw->ins [0]);
+ err |= __put_user(si, &rw->ins [1]);
+ err |= __put_user(uc, &rw->ins [2]);
+ err |= __put_user(sfp, &rw->ins [6]); /* frame pointer */
+ if (err)
+ goto sigsegv;
+
regs->u_regs[UREG_I0] = signr;
regs->u_regs[UREG_I1] = (uint) si;
regs->u_regs[UREG_I2] = (uint) uc;
@@ -783,8 +818,9 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
return;
sigill_and_return:
- lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ do_exit(SIGSEGV);
}
asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
@@ -792,13 +828,15 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
svr4_gregset_t *gr;
svr4_mcontext_t *mc;
svr4_sigset_t setv;
+ int err = 0;
synchronize_user_stack();
if (current->tss.w_saved)
goto sigsegv_and_return;
- if(clear_user(uc, sizeof (*uc)))
+ err = clear_user(uc, sizeof (*uc));
+ if (err)
return -EFAULT;
/* Setup convenience variables */
@@ -810,32 +848,31 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
if (_NSIG_WORDS >= 4) {
setv.sigbits[2] = current->blocked.sig[2];
setv.sigbits[3] = current->blocked.sig[3];
- __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
} else
- __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
+ err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
/* Store registers */
- __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
- __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]);
- __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]);
- __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
+ err |= __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
+ err |= __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]);
+ err |= __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]);
+ err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
/* Copy g [1..7] and o [0..7] registers */
- copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
- copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
+ err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
+ err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
/* Setup sigaltstack */
- __put_user(current->sas_ss_sp, &uc->stack.sp);
- __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
- __put_user(current->sas_ss_size, &uc->stack.size);
+ err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
+ err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+ err |= __put_user(current->sas_ss_size, &uc->stack.size);
/* The register file is not saved
* we have already stuffed all of it with sync_user_stack
*/
- return 0;
+ return (err ? -EFAULT : 0);
sigsegv_and_return:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -905,18 +942,19 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
spin_unlock_irq(&current->sigmask_lock);
regs->pc = pc;
regs->npc = npc | 1;
- __get_user(regs->y, &((*gr) [SVR4_Y]));
- __get_user(psr, &((*gr) [SVR4_PSR]));
+ err |= __get_user(regs->y, &((*gr) [SVR4_Y]));
+ err |= __get_user(psr, &((*gr) [SVR4_PSR]));
regs->psr &= ~(PSR_ICC);
regs->psr |= (psr & PSR_ICC);
/* Restore g[1..7] and o[0..7] registers */
- copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7);
- copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8);
- return 0;
+ err |= __copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1],
+ sizeof (long) * 7);
+ err |= __copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0],
+ sizeof (long) * 8);
+ return (err ? -EFAULT : 0);
sigsegv_and_return:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -1069,7 +1107,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
if(current->binfmt && current->binfmt->core_dump) {
lock_kernel();
- if(current->binfmt->core_dump(signr, regs))
+ if(current->binfmt &&
+ current->binfmt->core_dump &&
+ current->binfmt->core_dump(signr, regs))
exit_code |= 0x80;
unlock_kernel();
}