i386: fix recursive faults during oops when current is invalid
PATCH 1/1 i386: fix recursive faults during oops when current is invalid
Fix recursive faults during oops caused by invalid value in current by using __get_user()/__put_user() when dereferencing it.
Reported by Krzysztof Halasa <[email protected]>
Signed-off-by Chuck Ebbert <[email protected]>
---
If this is OK I'll do x86_64 next.
arch/i386/kernel/traps.c | 17 +++++++++++++---- arch/i386/mm/fault.c | 7 ++++--- 2 files changed, 17 insertions(+), 7 deletions(-)
arch/i386/mm/fault.c +4 -3
@@ -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 );
arch/i386/kernel/traps.c +13 -4
@@ -267,8 +267,16 @@ void show_registers(struct pt_regs *regsint i;int in_kernel =1 ;unsigned long esp; +char *comm ="<bad task>" ; +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)) {
@@ -291,8 +299,8 @@ void show_registers(struct pt_regs *regsprintk (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..
@@ -371,6 +379,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 ();
@@ -409,8 +418,8 @@ void die(const char * str, struct pt_reg#endif if (nl)printk ("\n" ); -if (notify_die (DIE_OOPS , str, regs, err, - current->thread.trap_no,SIGSEGV ) != +__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 */
Signature · 1 line
Chuck