예제 #1
0
파일: trap.c 프로젝트: ivucica/linux
/*
 * We give a *copy* of the faultinfo in the regs to segv.
 * This must be done, since nesting SEGVs could overwrite
 * the info in the regs. A pointer to the info then would
 * give us bad data!
 */
unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
{
	struct siginfo si;
	void *catcher;
	int err;
        int is_write = FAULT_WRITE(fi);
        unsigned long address = FAULT_ADDRESS(fi);

        if(!is_user && (address >= start_vm) && (address < end_vm)){
                flush_tlb_kernel_vm();
                return(0);
        }
	else if(current->mm == NULL)
		panic("Segfault with no mm");

	if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
		err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
	else {
		err = -EFAULT;
		/* A thread accessed NULL, we get a fault, but CR2 is invalid.
		 * This code is used in __do_copy_from_user() of TT mode. */
		address = 0;
	}

	catcher = current->thread.fault_catcher;
	if(!err)
		return(0);
	else if(catcher != NULL){
		current->thread.fault_addr = (void *) address;
		do_longjmp(catcher, 1);
	}
	else if(current->thread.fault_addr != NULL)
		panic("fault_addr set but no fault catcher");
        else if(!is_user && arch_fixup(ip, sc))
		return(0);

 	if(!is_user)
		panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
		      address, ip);

	if (err == -EACCES) {
		si.si_signo = SIGBUS;
		si.si_errno = 0;
		si.si_code = BUS_ADRERR;
		si.si_addr = (void __user *)address;
                current->thread.arch.faultinfo = fi;
		force_sig_info(SIGBUS, &si, current);
	} else if (err == -ENOMEM) {
		printk("VM: killing process %s\n", current->comm);
		do_exit(SIGKILL);
	} else {
		BUG_ON(err != -EFAULT);
		si.si_signo = SIGSEGV;
		si.si_addr = (void __user *) address;
                current->thread.arch.faultinfo = fi;
		force_sig_info(SIGSEGV, &si, current);
	}
	return(0);
}
예제 #2
0
static void handle_segv(int pid)
{
	struct ptrace_faultinfo fault;
	int err;

	err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
	if(err)
		panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
		      errno);

	segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
}
예제 #3
0
void segv_handler(int sig, union uml_pt_regs *regs)
{
	int index, max;
        struct faultinfo * fi = UPT_FAULTINFO(regs);

        if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){
                bad_segv(*fi, UPT_IP(regs));
		return;
	}
	max = sizeof(segfault_record)/sizeof(segfault_record[0]);
	index = next_trap_index(max);

	nsegfaults++;
        segfault_record[index].address = FAULT_ADDRESS(*fi);
	segfault_record[index].pid = os_getpid();
        segfault_record[index].is_write = FAULT_WRITE(*fi);
	segfault_record[index].sp = UPT_SP(regs);
	segfault_record[index].is_user = UPT_IS_USER(regs);
        segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
}
예제 #4
0
int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr)
{
  	struct sigcontext sc, *from = from_ptr;
	unsigned long fpregs[FP_FRAME_SIZE];
	int err;

	err = copy_from_user_proc(&sc, from, sizeof(sc));
	err |= copy_from_user_proc(fpregs, sc.fpstate, sizeof(fpregs));
	if(err)
		return(err);

	regs->skas.regs[GS] = sc.gs;
	regs->skas.regs[FS] = sc.fs;
	regs->skas.regs[ES] = sc.es;
	regs->skas.regs[DS] = sc.ds;
	regs->skas.regs[EDI] = sc.edi;
	regs->skas.regs[ESI] = sc.esi;
	regs->skas.regs[EBP] = sc.ebp;
	regs->skas.regs[UESP] = sc.esp;
	regs->skas.regs[EBX] = sc.ebx;
	regs->skas.regs[EDX] = sc.edx;
	regs->skas.regs[ECX] = sc.ecx;
	regs->skas.regs[EAX] = sc.eax;
	regs->skas.regs[EIP] = sc.eip;
	regs->skas.regs[CS] = sc.cs;
	regs->skas.regs[EFL] = sc.eflags;
	regs->skas.regs[SS] = sc.ss;
	regs->skas.fault_addr = sc.cr2;
	regs->skas.fault_type = FAULT_WRITE(sc.err);
	regs->skas.trap_type = sc.trapno;

	err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs);
	if(err < 0){
	  	printk("copy_sc_to_user - PTRACE_SETFPREGS failed, "
		       "errno = %d\n", errno);
		return(1);
	}

	return(0);
}
예제 #5
0
/*
 * We give a *copy* of the faultinfo in the regs to segv.
 * This must be done, since nesting SEGVs could overwrite
 * the info in the regs. A pointer to the info then would
 * give us bad data!
 */
unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
                   struct uml_pt_regs *regs)
{
    struct siginfo si;
    jmp_buf *catcher;
    int err;
    int is_write = FAULT_WRITE(fi);
    unsigned long address = FAULT_ADDRESS(fi);

    if (!is_user && (address >= start_vm) && (address < end_vm)) {
        flush_tlb_kernel_vm();
        return 0;
    }
    else if (current->mm == NULL) {
        show_regs(container_of(regs, struct pt_regs, regs));
        panic("Segfault with no mm");
    }

    if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
        err = handle_page_fault(address, ip, is_write, is_user,
                                &si.si_code);
    else {
        err = -EFAULT;
        /*
         * A thread accessed NULL, we get a fault, but CR2 is invalid.
         * This code is used in __do_copy_from_user() of TT mode.
         * XXX tt mode is gone, so maybe this isn't needed any more
         */
        address = 0;
    }

    catcher = current->thread.fault_catcher;
    if (!err)
        return 0;
    else if (catcher != NULL) {
        current->thread.fault_addr = (void *) address;
        UML_LONGJMP(catcher, 1);
    }
    else if (current->thread.fault_addr != NULL)
        panic("fault_addr set but no fault catcher");
    else if (!is_user && arch_fixup(ip, regs))
        return 0;

    if (!is_user) {
        show_regs(container_of(regs, struct pt_regs, regs));
        panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
              address, ip);
    }

    if (err == -EACCES) {
        si.si_signo = SIGBUS;
        si.si_errno = 0;
        si.si_code = BUS_ADRERR;
        si.si_addr = (void __user *)address;
        current->thread.arch.faultinfo = fi;
        force_sig_info(SIGBUS, &si, current);
    } else if (err == -ENOMEM) {
        printk(KERN_INFO "VM: killing process %s\n", current->comm);
        do_exit(SIGKILL);
    } else {
        BUG_ON(err != -EFAULT);
        si.si_signo = SIGSEGV;
        si.si_addr = (void __user *) address;
        current->thread.arch.faultinfo = fi;
        force_sig_info(SIGSEGV, &si, current);
    }
    return 0;
}