static int save_fpu_state_to_user_stack( struct sigcontext __user * sc, struct _fpstate __user * fpstate ) { if (__put_user(fpstate, &sc->fpstate)) return -EFAULT; return save_i387(fpstate); }
static int setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, struct pt_regs *regs, unsigned long mask) { int tmp, err = 0; tmp = 0; savesegment(gs, tmp); err |= __put_user(tmp, (unsigned int __user *)&sc->gs); savesegment(fs, tmp); err |= __put_user(tmp, (unsigned int __user *)&sc->fs); err |= __put_user(regs->xes, (unsigned int __user *)&sc->es); err |= __put_user(regs->xds, (unsigned int __user *)&sc->ds); err |= __put_user(regs->edi, &sc->edi); err |= __put_user(regs->esi, &sc->esi); err |= __put_user(regs->ebp, &sc->ebp); err |= __put_user(regs->esp, &sc->esp); err |= __put_user(regs->ebx, &sc->ebx); err |= __put_user(regs->edx, &sc->edx); err |= __put_user(regs->ecx, &sc->ecx); err |= __put_user(regs->eax, &sc->eax); err |= __put_user(current->thread.trap_no, &sc->trapno); err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user(regs->eip, &sc->eip); err |= __put_user(regs->xcs, (unsigned int __user *)&sc->cs); err |= __put_user(regs->eflags, &sc->eflags); err |= __put_user(regs->esp, &sc->esp_at_signal); err |= __put_user(regs->xss, (unsigned int __user *)&sc->ss); tmp = save_i387(fpstate); if (tmp < 0) err = 1; else err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); /* non-iBCS2 extensions.. */ err |= __put_user(mask, &sc->oldmask); err |= __put_user(current->thread.cr2, &sc->cr2); return err; }
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { struct rt_sigframe __user *frame; struct _fpstate __user *fp = NULL; int err = 0; struct task_struct *me = current; if (used_math()) { fp = get_stack(ka, regs, sizeof(struct _fpstate)); frame = (void __user *)round_down( (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) goto give_sigsegv; if (save_i387(fp) < 0) err |= -1; } else frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; if (ka->sa.sa_flags & SA_SIGINFO) { err |= copy_siginfo_to_user(&frame->info, info); if (err) goto give_sigsegv; } /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->rsp), &frame->uc.uc_stack.ss_flags); err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me); err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); if (sizeof(*set) == 16) { __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); } else err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. If provided, use a stub already in userspace. */ /* x86-64 should always use SA_RESTORER. */ if (ka->sa.sa_flags & SA_RESTORER) { err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { /* could use a vstub here */ goto give_sigsegv; } if (err) goto give_sigsegv; #ifdef DEBUG_SIG printk("%d old rip %lx old rsp %lx old rax %lx\n", current->pid,regs->rip,regs->rsp,regs->rax); #endif /* Set up registers for signal handler */ regs->rdi = sig; /* In case the signal handler was declared without prototypes */ regs->rax = 0; /* This also works for non SA_SIGINFO handlers because they expect the next argument after the signal number on the stack. */ regs->rsi = (unsigned long)&frame->info; regs->rdx = (unsigned long)&frame->uc; regs->rip = (unsigned long) ka->sa.sa_handler; regs->rsp = (unsigned long)frame; /* Set up the CS register to run signal handlers in 64-bit mode, even if the handler happens to be interrupting 32-bit code. */ regs->cs = __USER_CS; /* This, by contrast, has nothing to do with segment registers - see include/asm-x86_64/uaccess.h for details. */ set_fs(USER_DS); regs->eflags &= ~TF_MASK; if (test_thread_flag(TIF_SINGLESTEP)) ptrace_notify(SIGTRAP); #ifdef DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->rip, frame->pretcode); #endif return 0; give_sigsegv: force_sigsegv(sig, current); return -EFAULT; }
int setup_signal_stack_si(unsigned long stack_top, int sig, struct k_sigaction *ka, struct pt_regs * regs, siginfo_t *info, sigset_t *set) { struct rt_sigframe __user *frame; struct _fpstate __user *fp = NULL; int err = 0; struct task_struct *me = current; frame = (struct rt_sigframe __user *) round_down(stack_top - sizeof(struct rt_sigframe), 16) - 8; frame = (struct rt_sigframe *) ((unsigned long) frame - 128); if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) goto out; #if 0 /* XXX */ if (save_i387(fp) < 0) err |= -1; #endif if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto out; if (ka->sa.sa_flags & SA_SIGINFO) { err |= copy_siginfo_to_user(&frame->info, info); if (err) goto out; } /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), &frame->uc.uc_stack.ss_flags); err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); if (sizeof(*set) == 16) { __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); } else err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. If provided, use a stub already in userspace. */ /* x86-64 should always use SA_RESTORER. */ if (ka->sa.sa_flags & SA_RESTORER) err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); else /* could use a vstub here */ goto out; if (err) goto out; /* Set up registers for signal handler */ { struct exec_domain *ed = current_thread_info()->exec_domain; if (unlikely(ed && ed->signal_invmap && sig < 32)) sig = ed->signal_invmap[sig]; } PT_REGS_RDI(regs) = sig; /* In case the signal handler was declared without prototypes */ PT_REGS_RAX(regs) = 0; /* This also works for non SA_SIGINFO handlers because they expect the next argument after the signal number on the stack. */ PT_REGS_RSI(regs) = (unsigned long) &frame->info; PT_REGS_RDX(regs) = (unsigned long) &frame->uc; PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; PT_REGS_RSP(regs) = (unsigned long) frame; out: return(err); }
SCOPE void injector_entry(struct syscall_regs r, uint32_t old_vdso_ventry, uint32_t main_addr) { int err; /* build STDOUT_FILENO_INJ and STDERR_FILENO_INJ */ /* all INJ_XXXX messages are wrote to console through * STDOUT_FILENO_INJ and STDERR_FILENO_INJ, not the original * 1 and 2. This is for some targets which close 1 and 2, like * lighttpd. * STDOUT_FILENO_INJ and STDERR_FILENO_INJ are defined in injector_debug.h */ if (STDOUT_FILENO != STDOUT_FILENO_INJ) INTERNAL_SYSCALL(dup2, 2, STDOUT_FILENO, STDOUT_FILENO_INJ); if (STDERR_FILENO != STDERR_FILENO_INJ) INTERNAL_SYSCALL(dup2, 2, STDERR_FILENO, STDERR_FILENO_INJ); INJ_TRACE("Here! we come to injector!!!\n"); INJ_TRACE("wrapped_sigreturn=%p\n", wrapped_sigreturn); INJ_TRACE("wrapped_rt_sigreturn=%p\n", wrapped_rt_sigreturn); ASSERT(injector_opts.logger_threshold >= 4096, &r, "logger threshold %d is strange\n", injector_opts.logger_threshold); old_self_pid = self_pid = INTERNAL_SYSCALL(getpid, 0); if (injector_opts.untraced) { /* We need to restore sighandler's restorer here */ tracing = 0; unhook_sighandlers(); return; } tracing = 1; snprintf(logger_filename, 128, LOGGER_DIRECTORY"/%d.log", self_pid); INJ_TRACE("logger fn: %s\n", logger_filename); snprintf(ckpt_filename, 128, LOGGER_DIRECTORY"/%d.ckpt", self_pid); INJ_TRACE("ckpt fn: %s\n", ckpt_filename); int fd = INTERNAL_SYSCALL(open, 3, logger_filename, O_WRONLY|O_APPEND, 0664); INJ_TRACE("logger fd = %d\n", fd); ASSERT(fd > 0, &r, "open logger failed: %d\n", fd); /* dup the fd to LOGGER_FD */ err = INTERNAL_SYSCALL(dup2, 2, fd, LOGGER_FD); ASSERT(err == LOGGER_FD, &r, "dup2 failed: %d\n", err); INJ_TRACE("dup fd to %d\n", err); err = INTERNAL_SYSCALL(close, 1, fd); ASSERT(err == 0, &r, "close failed: %d\n", err); INJ_TRACE("close %d\n", fd); logger_fd = LOGGER_FD; /* save the sigprocmask */ INTERNAL_SYSCALL(rt_sigprocmask, 4, 0, NULL, &state_vector.sigmask, sizeof(state_vector.sigmask)); /* :NOTICE: */ /* We MUST adjust esp here. when loader call injector, it pushs * 2 int32_t onto stack, so the esp in 'r' cannot be used directly. */ save_i387(&fpustate_struct); r.esp += 8; make_checkpoint(ckpt_filename, &r, &fpustate_struct, NULL); r.esp -= 8; err = INTERNAL_SYSCALL(ftruncate, 2, logger_fd, 0); ASSERT(err == 0, &r, "ftruncate failed: %d\n", err); INJ_TRACE("main ip=0x%x:0x%x\n", main_addr, r.eip); INJ_TRACE("eax=%d\n", r.eax); }
SCOPE void wrapped_syscall(const struct syscall_regs r) { /* if we don't trace fork and clone, the * child process can set tracing to 0 */ if (!tracing) { uint32_t retval; call_syscall(r, retval); return; } /* we must set signal_regs very early. if we set it * inside ENTER/EXIT_SYSCALL, a signal may happen before this assignment. */ /* don't check IS_BREAK_SYSCALL. we allow embeded signal handler. */ /* if a signal raise, we will use signal_regs immediately. so don't worry about * override. (the signal handler will save this regs before any new syscall, and * the restorer needn't it). */ signal_regs = &r; /* if a signal raise outside a syscall, those 2 values should same. if not, thay are * different. */ __syscall_reenter_base = __syscall_reenter_counter; /* if a signal happened after this gate and before EXIT_SYSCALL, * we know this syscall is disturbed, when sigprocess making ckpts, * it needs to adjust registers. */ /* don't allow signal inside before_syscall. * if signal happened inside it, the logger may be disturbed. */ /* disable dignal before enter_syscall make sure the sysall's header * is written into log when potential signal raise */ DISABLE_SIGNAL(); ENTER_SYSCALL(); if (!replay) { uint32_t syscall_nr = r.orig_eax; INJ_SILENT("wrapped_syscall: %d\n", syscall_nr); before_syscall(&r); ENABLE_SIGNAL(); uint32_t retval; call_syscall(r, retval); DISABLE_SIGNAL(); /* write a flag to indicate syscall not be disturbed */ /* if this syscall disturbed, the next data in logger * may be a syscall_nr (if signal processing use syscall) or a -2 * (write by wrapped_(rt_)sigreturn). when replay, if see this -1, * we know this syscall ends normally. */ int16_t f = -1; if (!(is_fork_syscall(syscall_nr) && (retval == 0))) { int err; err = INTERNAL_SYSCALL(write, 3, logger_fd, &f, sizeof(f)); ASSERT(err == sizeof(f), &r, "write signal tag failed: %d\n", err); logger_sz += err; } /* don't allow signal in after_syscall. if signal happens * in it, the syscall handler may only write a part of log into * log file. when ckpt is made and resume, it will write the left, * makes the log file inconsistent. */ after_syscall(&r); INJ_SILENT("wrapped_syscall: %d over, retval=%d\n", syscall_nr, r.eax); /* in the assembly code, we have modify the 'eax'. */ /* check the logger sz */ INJ_SILENT("logger_sz = %d\n", logger_sz); /* don't switch when signal processing */ if ((logger_sz > injector_opts.logger_threshold) && (!IS_REENTER_SYSCALL())) { int err; /* we need to remake ckpt */ INJ_TRACE("make ckpt: eip=0x%x\n", r.eip); /* we still need to adjust esp: * when we come here, r.esp hold an 'ret' address for * coming 'ret'. */ ((struct syscall_regs*)(&r))->esp += 4; /* save fpustate */ save_i387(&fpustate_struct); make_checkpoint(ckpt_filename, (struct syscall_regs *)(&r), &fpustate_struct, NULL); ((struct syscall_regs*)(&r))->esp -= 4; /* truncate logger file */ err = INTERNAL_SYSCALL(ftruncate, 2, logger_fd, 0); ASSERT(err == 0, &r, "ftruncate failed: %d\n", err); /* reset logger_sz */ /* logger_sz have been reset in do_make_checkpoint */ /* logger_sz = 0; */ } EXIT_SYSCALL(); ENABLE_SIGNAL(); } else { /* this gate is useless in replay */ EXIT_SYSCALL(); ENABLE_SIGNAL(); INJ_SILENT("replay syscall, eax=%d\n", r.eax); uint32_t retval; retval = replay_syscall(&r); INJ_SILENT("syscall, eax=%d, replayed: %d\n", r.eax, retval); /* here we force to reset the eax */ (((volatile struct syscall_regs *)&r)->eax) = retval; } }
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { struct rt_sigframe __user *frame; struct _fpstate __user *fp = NULL; int err = 0; struct task_struct *me = current; if (used_math()) { fp = get_stack(ka, regs, sizeof(struct _fpstate)); frame = (void __user *)round_down( (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) goto give_sigsegv; if (save_i387(fp) < 0) err |= -1; } else frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; if (ka->sa.sa_flags & SA_SIGINFO) { err |= copy_siginfo_to_user(&frame->info, info); if (err) goto give_sigsegv; } /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags); err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me); err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); if (sizeof(*set) == 16) { __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); } else err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. If provided, use a stub already in userspace. */ /* x86-64 should always use SA_RESTORER. */ if (ka->sa.sa_flags & SA_RESTORER) { err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { /* could use a vstub here */ goto give_sigsegv; } if (err) goto give_sigsegv; /* Set up registers for signal handler */ regs->di = sig; /* In case the signal handler was declared without prototypes */ regs->ax = 0; /* This also works for non SA_SIGINFO handlers because they expect the next argument after the signal number on the stack. */ regs->si = (unsigned long)&frame->info; regs->dx = (unsigned long)&frame->uc; regs->ip = (unsigned long) ka->sa.sa_handler; regs->sp = (unsigned long)frame; /* Set up the CS register to run signal handlers in 64-bit mode, even if the handler happens to be interrupting 32-bit code. */ regs->cs = __USER_CS; return 0; give_sigsegv: force_sigsegv(sig, current); return -EFAULT; }