signal32.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 994 行 · 第 1/2 页

C
994
字号
{	sigset_t s;	compat_sigset_t s32;	struct timespec t;	int ret;	mm_segment_t old_fs = get_fs();	siginfo_t info;	if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))		return -EFAULT;	sigset_from_compat(&s, &s32);	if (uts && get_compat_timespec(&t, uts))		return -EFAULT;	set_fs(KERNEL_DS);	/* The __user pointer casts are valid because of the set_fs() */	ret = sys_rt_sigtimedwait((sigset_t __user *) &s,			uinfo ? (siginfo_t __user *) &info : NULL,			uts ? (struct timespec __user *) &t : NULL,			sigsetsize);	set_fs(old_fs);	if (ret >= 0 && uinfo) {		if (copy_siginfo_to_user32(uinfo, &info))			return -EFAULT;	}	return ret;}/* * Note: it is necessary to treat pid and sig as unsigned ints, with the * corresponding cast to a signed int to insure that the proper conversion * (sign extension) between the register representation of a signed int * (msr in 32-bit mode) and the register representation of a signed int * (msr in 64-bit mode) is performed. */long sys32_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo){	siginfo_t info;	int ret;	mm_segment_t old_fs = get_fs();		if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||	    copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE32))		return -EFAULT;	set_fs (KERNEL_DS);	/* The __user pointer cast is valid becasuse of the set_fs() */	ret = sys_rt_sigqueueinfo((int)pid, (int)sig, (siginfo_t __user *) &info);	set_fs (old_fs);	return ret;}int sys32_rt_sigsuspend(compat_sigset_t __user * unewset, size_t sigsetsize, int p3,		int p4, int p6, int p7, struct pt_regs *regs){	sigset_t saveset, newset;	compat_sigset_t s32;	/* XXX: Don't preclude handling different sized sigset_t's.  */	if (sigsetsize != sizeof(sigset_t))		return -EINVAL;	if (copy_from_user(&s32, unewset, sizeof(s32)))		return -EFAULT;	/*	 * Swap the 2 words of the 64-bit sigset_t (they are stored	 * in the "wrong" endian in 32-bit user storage).	 */	sigset_from_compat(&newset, &s32);	sigdelsetmask(&newset, ~_BLOCKABLE);	spin_lock_irq(&current->sighand->siglock);	saveset = current->blocked;	current->blocked = newset;	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);	regs->result = -EINTR;	regs->gpr[3] = EINTR;	regs->ccr |= 0x10000000;	while (1) {		current->state = TASK_INTERRUPTIBLE;		schedule();		if (do_signal32(&saveset, regs))			/*			 * If a signal handler needs to be called,			 * do_signal32() has set R3 to the signal number (the			 * first argument of the signal handler), so don't			 * overwrite that with EINTR !			 * In the other cases, do_signal32() doesn't touch 			 * R3, so it's still set to -EINTR (see above).			 */			return regs->gpr[3];	}}/* *  Start Alternate signal stack support * *  System Calls *       sigaltatck               sys32_sigaltstack */int sys32_sigaltstack(u32 __new, u32 __old, int r5,		      int r6, int r7, int r8, struct pt_regs *regs){	stack_32_t __user * newstack = (stack_32_t __user *)(long) __new;	stack_32_t __user * oldstack = (stack_32_t __user *)(long) __old;	stack_t uss, uoss;	int ret;	mm_segment_t old_fs;	unsigned long sp;	compat_uptr_t ss_sp;	/*	 * set sp to the user stack on entry to the system call	 * the system call router sets R9 to the saved registers	 */	sp = regs->gpr[1];	/* Put new stack info in local 64 bit stack struct */	if (newstack) {		if (get_user(ss_sp, &newstack->ss_sp) ||		    __get_user(uss.ss_flags, &newstack->ss_flags) ||		    __get_user(uss.ss_size, &newstack->ss_size))			return -EFAULT;		uss.ss_sp = compat_ptr(ss_sp);	}	old_fs = get_fs();	set_fs(KERNEL_DS);	/* The __user pointer casts are valid because of the set_fs() */	ret = do_sigaltstack(		newstack ? (stack_t __user *) &uss : NULL,		oldstack ? (stack_t __user *) &uoss : NULL,		sp);	set_fs(old_fs);	/* Copy the stack information to the user output buffer */	if (!ret && oldstack  &&		(put_user((long)uoss.ss_sp, &oldstack->ss_sp) ||		 __put_user(uoss.ss_flags, &oldstack->ss_flags) ||		 __put_user(uoss.ss_size, &oldstack->ss_size)))		return -EFAULT;	return ret;}/* * Set up a signal frame for a "real-time" signal handler * (one which gets siginfo). */static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,			       siginfo_t *info, sigset_t *oldset,			       struct pt_regs * regs, unsigned long newsp){	struct rt_sigframe32 __user *rt_sf;	struct mcontext32 __user *frame;	unsigned long origsp = newsp;	compat_sigset_t c_oldset;	/* Set up Signal Frame */	/* Put a Real Time Context onto stack */	newsp -= sizeof(*rt_sf);	rt_sf = (struct rt_sigframe32 __user *)newsp;	/* create a stack frame for the caller of the handler */	newsp -= __SIGNAL_FRAMESIZE32 + 16;	if (verify_area(VERIFY_WRITE, (void __user *)newsp, origsp - newsp))		goto badframe;	compat_from_sigset(&c_oldset, oldset);	/* Put the siginfo & fill in most of the ucontext */	if (copy_siginfo_to_user32(&rt_sf->info, info)	    || __put_user(0, &rt_sf->uc.uc_flags)	    || __put_user(0, &rt_sf->uc.uc_link)	    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)	    || __put_user(sas_ss_flags(regs->gpr[1]),			  &rt_sf->uc.uc_stack.ss_flags)	    || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)	    || __put_user((u32)(u64)&rt_sf->uc.uc_mcontext, &rt_sf->uc.uc_regs)	    || __copy_to_user(&rt_sf->uc.uc_sigmask, &c_oldset, sizeof(c_oldset)))		goto badframe;	/* Save user registers on the stack */	frame = &rt_sf->uc.uc_mcontext;	if (save_user_regs(regs, frame, __NR_rt_sigreturn))		goto badframe;	if (put_user(regs->gpr[1], (unsigned long __user *)newsp))		goto badframe;	regs->gpr[1] = (unsigned long) newsp;	regs->gpr[3] = sig;	regs->gpr[4] = (unsigned long) &rt_sf->info;	regs->gpr[5] = (unsigned long) &rt_sf->uc;	regs->gpr[6] = (unsigned long) rt_sf;	regs->nip = (unsigned long) ka->sa.sa_handler;	regs->link = (unsigned long) frame->tramp;	regs->trap = 0;	regs->result = 0;	return;badframe:#if DEBUG_SIG	printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",	       regs, frame, newsp);#endif	force_sigsegv(sig, current);}static long do_setcontext32(struct ucontext32 __user *ucp, struct pt_regs *regs, int sig){	compat_sigset_t c_set;	sigset_t set;	u32 mcp;	if (__copy_from_user(&c_set, &ucp->uc_sigmask, sizeof(c_set))	    || __get_user(mcp, &ucp->uc_regs))		return -EFAULT;	sigset_from_compat(&set, &c_set);	restore_sigmask(&set);	if (restore_user_regs(regs, (struct mcontext32 __user *)(u64)mcp, sig))		return -EFAULT;	return 0;}/* * Handle {get,set,swap}_context operations for 32 bits processes */long sys32_swapcontext(struct ucontext32 __user *old_ctx,		       struct ucontext32 __user *new_ctx,		       int ctx_size, int r6, int r7, int r8, struct pt_regs *regs){	unsigned char tmp;	compat_sigset_t c_set;	/* Context size is for future use. Right now, we only make sure	 * we are passed something we understand	 */	if (ctx_size < sizeof(struct ucontext32))		return -EINVAL;	if (old_ctx != NULL) {		compat_from_sigset(&c_set, &current->blocked);		if (verify_area(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))		    || save_user_regs(regs, &old_ctx->uc_mcontext, 0)		    || __copy_to_user(&old_ctx->uc_sigmask, &c_set, sizeof(c_set))		    || __put_user((u32)(u64)&old_ctx->uc_mcontext, &old_ctx->uc_regs))			return -EFAULT;	}	if (new_ctx == NULL)		return 0;	if (verify_area(VERIFY_READ, new_ctx, sizeof(*new_ctx))	    || __get_user(tmp, (u8 __user *) new_ctx)	    || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1))		return -EFAULT;	/*	 * If we get a fault copying the context into the kernel's	 * image of the user's registers, we can't just return -EFAULT	 * because the user's registers will be corrupted.  For instance	 * the NIP value may have been updated but not some of the	 * other registers.  Given that we have done the verify_area	 * and successfully read the first and last bytes of the region	 * above, this should only happen in an out-of-memory situation	 * or if another thread unmaps the region containing the context.	 * We kill the task with a SIGSEGV in this situation.	 */	if (do_setcontext32(new_ctx, regs, 0))		do_exit(SIGSEGV);	return 0;}long sys32_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,		     struct pt_regs *regs){	struct rt_sigframe32 __user *rt_sf;	int ret;	/* Always make any pending restarted system calls return -EINTR */	current_thread_info()->restart_block.fn = do_no_restart_syscall;	rt_sf = (struct rt_sigframe32 __user *)		(regs->gpr[1] + __SIGNAL_FRAMESIZE32 + 16);	if (verify_area(VERIFY_READ, rt_sf, sizeof(*rt_sf)))		goto bad;	if (do_setcontext32(&rt_sf->uc, regs, 1))		goto bad;	/*	 * It's not clear whether or why it is desirable to save the	 * sigaltstack setting on signal delivery and restore it on	 * signal return.  But other architectures do this and we have	 * always done it up until now so it is probably better not to	 * change it.  -- paulus	 * We use the sys32_ version that does the 32/64 bits conversion	 * and takes userland pointer directly. What about error checking ?	 * nobody does any...	 */       	sys32_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs);	ret = regs->result;	return ret; bad:	force_sig(SIGSEGV, current);	return 0;}/* * OK, we're invoking a handler */static void handle_signal32(unsigned long sig, struct k_sigaction *ka,			    siginfo_t *info, sigset_t *oldset,			    struct pt_regs * regs, unsigned long newsp){	struct sigcontext32 __user *sc;	struct sigregs32 __user *frame;	unsigned long origsp = newsp;	/* Set up Signal Frame */	newsp -= sizeof(struct sigregs32);	frame = (struct sigregs32 __user *) newsp;	/* Put a sigcontext on the stack */	newsp -= sizeof(*sc);	sc = (struct sigcontext32 __user *) newsp;	/* create a stack frame for the caller of the handler */	newsp -= __SIGNAL_FRAMESIZE32;	if (verify_area(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))		goto badframe;#if _NSIG != 64#error "Please adjust handle_signal32()"#endif	if (__put_user((u32)(u64)ka->sa.sa_handler, &sc->handler)	    || __put_user(oldset->sig[0], &sc->oldmask)	    || __put_user((oldset->sig[0] >> 32), &sc->_unused[3])	    || __put_user((u32)(u64)frame, &sc->regs)	    || __put_user(sig, &sc->signal))		goto badframe;	if (save_user_regs(regs, &frame->mctx, __NR_sigreturn))		goto badframe;	if (put_user(regs->gpr[1], (unsigned long __user *)newsp))		goto badframe;	regs->gpr[1] = (unsigned long) newsp;	regs->gpr[3] = sig;	regs->gpr[4] = (unsigned long) sc;	regs->nip = (unsigned long) ka->sa.sa_handler;	regs->link = (unsigned long) frame->mctx.tramp;	regs->trap = 0;	regs->result = 0;	return;badframe:#if DEBUG_SIG	printk("badframe in handle_signal, regs=%p frame=%x newsp=%x\n",	       regs, frame, *newspp);#endif	force_sigsegv(sig, current);}/* * Do a signal return; undo the signal stack. */long sys32_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,		       struct pt_regs *regs){	struct sigcontext32 __user *sc;	struct sigcontext32 sigctx;	struct mcontext32 __user *sr;	sigset_t set;	int ret;	/* Always make any pending restarted system calls return -EINTR */	current_thread_info()->restart_block.fn = do_no_restart_syscall;	sc = (struct sigcontext32 __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))		goto badframe;	/*	 * Note that PPC32 puts the upper 32 bits of the sigmask in the	 * unused part of the signal stackframe	 */	set.sig[0] = sigctx.oldmask + ((long)(sigctx._unused[3]) << 32);	restore_sigmask(&set);	sr = (struct mcontext32 __user *)(u64)sigctx.regs;	if (verify_area(VERIFY_READ, sr, sizeof(*sr))	    || restore_user_regs(regs, sr, 1))		goto badframe;	ret = regs->result;	return ret;badframe:	force_sig(SIGSEGV, current);	return 0;}/* *  Start of do_signal32 routine * *   This routine gets control when a pending signal needs to be processed *     in the 32 bit target thread - * *   It handles both rt and non-rt signals *//* * 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. */int do_signal32(sigset_t *oldset, struct pt_regs *regs){	siginfo_t info;	unsigned int frame, newsp;	int signr, ret;	struct k_sigaction ka;	if (!oldset)		oldset = &current->blocked;	newsp = frame = 0;	signr = get_signal_to_deliver(&info, &ka, regs, NULL);	if (TRAP(regs) == 0x0C00		/* System Call! */	    && regs->ccr & 0x10000000		/* error signalled */	    && ((ret = regs->gpr[3]) == ERESTARTSYS		|| ret == ERESTARTNOHAND || ret == ERESTARTNOINTR		|| ret == ERESTART_RESTARTBLOCK)) {		if (signr > 0		    && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK			|| (ret == ERESTARTSYS			    && !(ka.sa.sa_flags & SA_RESTART)))) {			/* make the system call return an EINTR error */			regs->result = -EINTR;			regs->gpr[3] = EINTR;			/* note that the cr0.SO bit is already set */		} else {			regs->nip -= 4;	/* Back up & retry system call */			regs->result = 0;			regs->trap = 0;			if (ret == ERESTART_RESTARTBLOCK)				regs->gpr[0] = __NR_restart_syscall;			else				regs->gpr[3] = regs->orig_gpr3;		}	}	if (signr == 0)		return 0;		/* no signals delivered */	if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size	    && (!on_sig_stack(regs->gpr[1])))		newsp = (current->sas_ss_sp + current->sas_ss_size);	else		newsp = regs->gpr[1];	newsp &= ~0xfUL;	/* Whee!  Actually deliver the signal.  */	if (ka.sa.sa_flags & SA_SIGINFO)		handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp);	else		handle_signal32(signr, &ka, &info, oldset, regs, newsp);	if (!(ka.sa.sa_flags & SA_NODEFER)) {		spin_lock_irq(&current->sighand->siglock);		sigorsets(&current->blocked, &current->blocked,			  &ka.sa.sa_mask);		sigaddset(&current->blocked, signr);		recalc_sigpending();		spin_unlock_irq(&current->sighand->siglock);	}	return 1;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?