// SPDX-License-Identifier: GPL-2.0 /* linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
/* Checks if the fp is valid. We always build signal frames which are * 16-byte aligned, therefore we can always enforce that the restore * frame has that property as well.
*/ staticinlinebool invalid_frame_pointer(void __user *fp, int fplen)
{ if ((((unsignedlong) fp) & 15) || !access_ok(fp, fplen)) returntrue;
err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save)
err |= restore_fpu_state(regs, fpu_save);
err |= __get_user(rwin_save, &sf->rwin_save); if (rwin_save)
err |= restore_rwin_state(rwin_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(unsignedint));
/* * If we are on the alternate signal stack and would overflow it, don't. * Return an always-bogus address instead so we will die with SIGSEGV.
*/ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) return (void __user *) -1L;
/* This is the X/Open sanctioned signal stack switching. */
sp = sigsp(sp, ksig) - framesize;
/* Always align the stack frame. This handles two cases. First, * sigaltstack need not be mindful of platform specific stack * alignment. Second, if we took this signal because the stack * is not aligned properly, we'd like to take the signal cleanly * and report that.
*/
sp &= ~15UL;
staticinlinevoid syscall_restart(unsignedlong orig_i0, struct pt_regs *regs, struct sigaction *sa)
{ switch(regs->u_regs[UREG_I0]) { case ERESTART_RESTARTBLOCK: case ERESTARTNOHAND:
no_system_call_restart:
regs->u_regs[UREG_I0] = EINTR;
regs->psr |= PSR_C; break; case ERESTARTSYS: if (!(sa->sa_flags & SA_RESTART)) goto no_system_call_restart;
fallthrough; case ERESTARTNOINTR:
regs->u_regs[UREG_I0] = orig_i0;
regs->pc -= 4;
regs->npc -= 4;
}
}
/* Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake.
*/ staticvoid do_signal(struct pt_regs *regs, unsignedlong orig_i0)
{ struct ksignal ksig; int restart_syscall; bool has_handler;
/* It's a lot of work and synchronization to add a new ptrace * register for GDB to save and restore in order to get * orig_i0 correct for syscall restarts when debugging. * * Although it should be the case that most of the global * registers are volatile across a system call, glibc already * depends upon that fact that we preserve them. So we can't * just use any global register to save away the orig_i0 value. * * In particular %g2, %g3, %g4, and %g5 are all assumed to be * preserved across a system call trap by various pieces of * code in glibc. * * %g7 is used as the "thread register". %g6 is not used in * any fixed manner. %g6 is used as a scratch register and * a compiler temporary, but its value is never used across * a system call. Therefore %g6 is usable for orig_i0 storage.
*/ if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
regs->u_regs[UREG_G6] = orig_i0;
has_handler = get_signal(&ksig);
/* If the debugger messes with the program counter, it clears * the software "in syscall" bit, directing us to not perform * a syscall restart.
*/
restart_syscall = 0; if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) {
restart_syscall = 1;
orig_i0 = regs->u_regs[UREG_G6];
}
if (has_handler) { if (restart_syscall)
syscall_restart(orig_i0, regs, &ksig.ka.sa);
handle_signal(&ksig, regs);
} else { if (restart_syscall) { switch (regs->u_regs[UREG_I0]) { case ERESTARTNOHAND: case ERESTARTSYS: case ERESTARTNOINTR: /* replay the system call when we are done */
regs->u_regs[UREG_I0] = orig_i0;
regs->pc -= 4;
regs->npc -= 4;
pt_regs_clear_syscall(regs);
fallthrough; case ERESTART_RESTARTBLOCK:
regs->u_regs[UREG_G1] = __NR_restart_syscall;
regs->pc -= 4;
regs->npc -= 4;
pt_regs_clear_syscall(regs);
}
}
restore_saved_sigmask();
}
}
asmlinkage int do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr, unsignedlong sp)
{ int ret = -EFAULT;
/* First see if old state is wanted. */ if (ossptr) { if (put_user(current->sas_ss_sp + current->sas_ss_size,
&ossptr->the_stack) ||
__put_user(on_sig_stack(sp), &ossptr->cur_status)) goto out;
}
/* Now see if we want to update the new state. */ if (ssptr) { char *ss_sp;
if (get_user(ss_sp, &ssptr->the_stack)) goto out; /* If the current stack was set with sigaltstack, don't
swap stacks while we are on it. */
ret = -EPERM; if (current->sas_ss_sp && on_sig_stack(sp)) goto out;
/* Since we don't know the extent of the stack, and we don't track onstack-ness, but rather calculate it, we must
presume a size. Ho hum this interface is lossy. */
current->sas_ss_sp = (unsignedlong)ss_sp - SIGSTKSZ;
current->sas_ss_size = SIGSTKSZ;
}
ret = 0;
out: return ret;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.