Ejemplo n.º 1
0
static long
setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr)
{
	extern char __kernel_sigtramp[];
	unsigned long tramp_addr, new_rbs = 0, new_sp;
	struct sigframe __user *frame;
	long err;

	new_sp = scr->pt.r12;
	tramp_addr = (unsigned long) __kernel_sigtramp;
	if (ksig->ka.sa.sa_flags & SA_ONSTACK) {
		int onstack = sas_ss_flags(new_sp);

		if (onstack == 0) {
			new_sp = current->sas_ss_sp + current->sas_ss_size;
			/*
			 * We need to check for the register stack being on the
			 * signal stack separately, because it's switched
			 * separately (memory stack is switched in the kernel,
			 * register stack is switched in the signal trampoline).
			 */
			if (!rbs_on_sig_stack(scr->pt.ar_bspstore))
				new_rbs = ALIGN(current->sas_ss_sp,
						sizeof(long));
		} else if (onstack == SS_ONSTACK) {
			unsigned long check_sp;

			/*
			 * 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.
			 */
			check_sp = (new_sp - sizeof(*frame)) & -STACK_ALIGN;
			if (!likely(on_sig_stack(check_sp)))
				return force_sigsegv_info(ksig->sig, (void __user *)
							  check_sp);
		}
	}
	frame = (void __user *) ((new_sp - sizeof(*frame)) & -STACK_ALIGN);

	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
		return force_sigsegv_info(ksig->sig, frame);

	err  = __put_user(ksig->sig, &frame->arg0);
	err |= __put_user(&frame->info, &frame->arg1);
	err |= __put_user(&frame->sc, &frame->arg2);
	err |= __put_user(new_rbs, &frame->sc.sc_rbs_base);
	err |= __put_user(0, &frame->sc.sc_loadrs);	/* initialize to zero */
	err |= __put_user(ksig->ka.sa.sa_handler, &frame->handler);

	err |= copy_siginfo_to_user(&frame->info, &ksig->info);

	err |= __save_altstack(&frame->sc.sc_stack, scr->pt.r12);
	err |= setup_sigcontext(&frame->sc, set, scr);

	if (unlikely(err))
		return force_sigsegv_info(ksig->sig, frame);

	scr->pt.r12 = (unsigned long) frame - 16;	/* new stack pointer */
	scr->pt.ar_fpsr = FPSR_DEFAULT;			/* reset fpsr for signal handler */
	scr->pt.cr_iip = tramp_addr;
	ia64_psr(&scr->pt)->ri = 0;			/* start executing in first slot */
	ia64_psr(&scr->pt)->be = 0;			/* force little-endian byte-order */
	/*
	 * Force the interruption function mask to zero.  This has no effect when a
	 * system-call got interrupted by a signal (since, in that case, scr->pt_cr_ifs is
	 * ignored), but it has the desirable effect of making it possible to deliver a
	 * signal with an incomplete register frame (which happens when a mandatory RSE
	 * load faults).  Furthermore, it has no negative effect on the getting the user's
	 * dirty partition preserved, because that's governed by scr->pt.loadrs.
	 */
	scr->pt.cr_ifs = (1UL << 63);

	/*
	 * Note: this affects only the NaT bits of the scratch regs (the ones saved in
	 * pt_regs), which is exactly what we want.
	 */
	scr->scratch_unat = 0; /* ensure NaT bits of r12 is clear */

#if DEBUG_SIG
	printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%p\n",
	       current->comm, current->pid, ksig->sig, scr->pt.r12, frame->sc.sc_ip, frame->handler);
#endif
	return 0;
}
Ejemplo n.º 2
0
static long
setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
	     struct sigscratch *scr)
{
	extern char ia64_sigtramp[], __start_gate_section[];
	unsigned long tramp_addr, new_rbs = 0;
	struct sigframe *frame;
	struct siginfo si;
	long err;

	frame = (void *) scr->pt.r12;
	tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section);
	if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) {
		frame = (void *) ((current->sas_ss_sp + current->sas_ss_size)
				  & ~(STACK_ALIGN - 1));
		/*
		 * We need to check for the register stack being on the signal stack
		 * separately, because it's switched separately (memory stack is switched
		 * in the kernel, register stack is switched in the signal trampoline).
		 */
		if (!rbs_on_sig_stack(scr->pt.ar_bspstore))
			new_rbs  = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
	}
	frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1));

	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
		goto give_sigsegv;

	err  = __put_user(sig, &frame->arg0);
	err |= __put_user(&frame->info, &frame->arg1);
	err |= __put_user(&frame->sc, &frame->arg2);
	err |= __put_user(new_rbs, &frame->sc.sc_rbs_base);
	err |= __put_user(0, &frame->sc.sc_loadrs);	/* initialize to zero */
	err |= __put_user(ka->sa.sa_handler, &frame->handler);

	err |= copy_siginfo_to_user(&frame->info, info);

	err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp);
	err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size);
	err |= __put_user(sas_ss_flags(scr->pt.r12), &frame->sc.sc_stack.ss_flags);
	err |= setup_sigcontext(&frame->sc, set, scr);

	if (err)
		goto give_sigsegv;

	scr->pt.r12 = (unsigned long) frame - 16;	/* new stack pointer */
	scr->pt.ar_fpsr = FPSR_DEFAULT;			/* reset fpsr for signal handler */
	scr->pt.cr_iip = tramp_addr;
	ia64_psr(&scr->pt)->ri = 0;			/* start executing in first slot */
	/*
	 * Force the interruption function mask to zero.  This has no effect when a
	 * system-call got interrupted by a signal (since, in that case, scr->pt_cr_ifs is
	 * ignored), but it has the desirable effect of making it possible to deliver a
	 * signal with an incomplete register frame (which happens when a mandatory RSE
	 * load faults).  Furthermore, it has no negative effect on the getting the user's
	 * dirty partition preserved, because that's governed by scr->pt.loadrs.
	 */
	scr->pt.cr_ifs = (1UL << 63);

	/*
	 * Note: this affects only the NaT bits of the scratch regs (the ones saved in
	 * pt_regs), which is exactly what we want.
	 */
	scr->scratch_unat = 0; /* ensure NaT bits of r12 is clear */

#if DEBUG_SIG
	printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n",
	       current->comm, current->pid, sig, scr->pt.r12, scr->pt.cr_iip, scr->pt.r3);
#endif
	return 1;

  give_sigsegv:
	if (sig == SIGSEGV)
		ka->sa.sa_handler = SIG_DFL;
	si.si_signo = SIGSEGV;
	si.si_errno = 0;
	si.si_code = SI_KERNEL;
	si.si_pid = current->pid;
	si.si_uid = current->uid;
	si.si_addr = frame;
	force_sig_info(SIGSEGV, &si, current);
	return 0;
}