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(-)
--- 2.6.18-rc1-32.orig/arch/i386/mm/fault.c
+++ 2.6.18-rc1-32/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);
--- 2.6.18-rc1-32.orig/arch/i386/kernel/traps.c
+++ 2.6.18-rc1-32/arch/i386/kernel/traps.c
@@ -267,8 +267,16 @@ void show_registers(struct pt_regs *regs
int 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 *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..
@@ -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 */
--
Chuck
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]