signal32.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 998 行 · 第 1/2 页
C
998 行
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(¤t->sighand->siglock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(); spin_unlock_irq(¤t->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 if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, 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, ¤t->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 if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, 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; struct k_sigaction *ka; unsigned int frame, newsp; int signr, ret; if (!oldset) oldset = ¤t->blocked; newsp = frame = 0; signr = get_signal_to_deliver(&info, regs, NULL); ka = (signr == 0)? NULL: ¤t->sighand->action[signr-1]; 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_ONESHOT) ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } return 1;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?