From: Chuck Ebbert <76306.1226@compuserve.com> Fix recursive faults during oops caused by invalid value in current by using __get_user()/__put_user() when dereferencing it. Reported by Krzysztof Halasa Signed-off-by: Chuck Ebbert <76306.1226@compuserve.com> Cc: Andi Kleen Signed-off-by: Andrew Morton --- arch/i386/kernel/traps.c | 18 ++++++++++++++---- arch/i386/mm/fault.c | 7 ++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff -puN arch/i386/kernel/traps.c~i386-fix-recursive-faults-during-oops-when-current arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c~i386-fix-recursive-faults-during-oops-when-current +++ a/arch/i386/kernel/traps.c @@ -278,8 +278,16 @@ void show_registers(struct pt_regs *regs int i; int in_kernel = 1; unsigned long esp; + char *comm = ""; + pid_t pid = 0; + void *thread_info = 0; unsigned short ss; + __get_user(thread_info, ¤t->thread_info); + __get_user(pid, ¤t->pid); + if (!__get_user(comm, (char **)current->comm)) + comm = current->comm; + esp = (unsigned long) (®s->esp); savesegment(ss, ss); if (user_mode_vm(regs)) { @@ -302,8 +310,8 @@ void show_registers(struct pt_regs *regs printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n", regs->xds & 0xffff, regs->xes & 0xffff, ss); printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", - TASK_COMM_LEN, current->comm, current->pid, - current_thread_info(), current, current->thread_info); + TASK_COMM_LEN, comm, pid, + current_thread_info(), current, thread_info); /* * When in-kernel, we also print out the stack and code at the * time of the fault.. @@ -382,6 +390,7 @@ void die(const char * str, struct pt_reg }; static int die_counter; unsigned long flags; + unsigned long trap_no = 0; /* default if task pointer is corrupt */ oops_enter(); @@ -414,8 +423,9 @@ void die(const char * str, struct pt_reg #endif printk("\n"); sysfs_printk_last_file(); - if (notify_die(DIE_OOPS, str, regs, err, - current->thread.trap_no, SIGSEGV) != NOTIFY_STOP) { + __get_user(trap_no, ¤t->thread.trap_no); + if (notify_die(DIE_OOPS, str, regs, err, trap_no, SIGSEGV) != + NOTIFY_STOP) { show_registers(regs); /* Executive summary in case the oops scrolled away */ esp = (unsigned long) (®s->esp); diff -puN arch/i386/mm/fault.c~i386-fix-recursive-faults-during-oops-when-current arch/i386/mm/fault.c --- a/arch/i386/mm/fault.c~i386-fix-recursive-faults-during-oops-when-current +++ a/arch/i386/mm/fault.c @@ -585,9 +585,10 @@ no_context: printk(KERN_ALERT "*pte = %08lx\n", page); } #endif - tsk->thread.cr2 = address; - tsk->thread.trap_no = 14; - tsk->thread.error_code = error_code; + /* avoid possible fault here if tsk is garbage */ + __put_user(address, &tsk->thread.cr2); + __put_user(14, &tsk->thread.trap_no); + __put_user(error_code, &tsk->thread.error_code); die("Oops", regs, error_code); bust_spinlocks(0); do_exit(SIGKILL); _