--- zzzz-none-000/linux-2.6.19.2/arch/i386/kernel/traps.c 2007-01-10 19:10:37.000000000 +0000 +++ davinci-8020-5504/linux-2.6.19.2/arch/i386/kernel/traps.c 2007-01-19 14:42:56.000000000 +0000 @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef CONFIG_EISA #include @@ -61,18 +62,10 @@ asmlinkage int system_call(void); -struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0, 0 }, { 0, 0 } }; - /* Do we ignore FPU interrupts ? */ char ignore_fpu_irq = 0; -/* - * The IDT has to be page-aligned to simplify the Pentium - * F0 0F bug workaround.. We have a special link segment - * for this. - */ -struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; +extern struct desc_struct idt_table[256]; asmlinkage void divide_error(void); asmlinkage void debug(void); @@ -129,24 +122,20 @@ #ifdef CONFIG_FRAME_POINTER while (valid_stack_ptr(tinfo, (void *)ebp)) { - unsigned long new_ebp; addr = *(unsigned long *)(ebp + 4); ops->address(data, addr); /* * break out of recursive entries (such as - * end_of_stack_stop_unwind_function). Also, - * we can never allow a frame pointer to - * move downwards! + * end_of_stack_stop_unwind_function): */ - new_ebp = *(unsigned long *)ebp; - if (new_ebp <= ebp) + if (ebp == *(unsigned long *)ebp) break; - ebp = new_ebp; + ebp = *(unsigned long *)ebp; } #else while (valid_stack_ptr(tinfo, stack)) { addr = *stack++; - if (__kernel_text_address(addr)) + if (__kernel_text_address(addr + __KERNEL_TEXT_OFFSET)) ops->address(data, addr); } #endif @@ -351,7 +340,7 @@ esp = (unsigned long) (®s->esp); savesegment(ss, ss); - if (user_mode_vm(regs)) { + if (user_mode(regs)) { in_kernel = 0; esp = regs->esp; ss = regs->xss & 0xffff; @@ -382,13 +371,15 @@ u8 __user *eip; int code_bytes = 64; unsigned char c; + mm_segment_t old_fs = get_fs(); printk("\n" KERN_EMERG "Stack: "); show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG); printk(KERN_EMERG "Code: "); - eip = (u8 __user *)regs->eip - 43; + set_fs(KERNEL_DS); + eip = (u8 __user *)regs->eip - 43 + __KERNEL_TEXT_OFFSET; if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { /* try starting at EIP */ eip = (u8 __user *)regs->eip; @@ -399,26 +390,29 @@ printk(" Bad EIP value."); break; } - if (eip == (u8 __user *)regs->eip) + if (eip == (u8 __user *)regs->eip + __KERNEL_TEXT_OFFSET) printk("<%02x> ", c); else printk("%02x ", c); } + set_fs(old_fs); } printk("\n"); } static void handle_BUG(struct pt_regs *regs) { - unsigned long eip = regs->eip; + unsigned long eip = regs->eip + __KERNEL_TEXT_OFFSET; unsigned short ud2; + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); if (eip < PAGE_OFFSET) - return; + goto out; if (probe_kernel_address((unsigned short __user *)eip, ud2)) - return; + goto out; if (ud2 != 0x0b0f) - return; + goto out; printk(KERN_EMERG "------------[ cut here ]------------\n"); @@ -428,18 +422,21 @@ char *file; char c; - if (probe_kernel_address((unsigned short __user *)(eip + 2), - line)) + if (probe_kernel_address((unsigned short __user *)(eip + 7), line)) break; - if (__get_user(file, (char * __user *)(eip + 4)) || - (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) + if (probe_kernel_address((char * __user *)(eip + 3), file) || + file < _text + __KERNEL_TEXT_OFFSET) + break; + if (probe_kernel_address(file, c)) file = ""; - printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); - return; + goto out; } while (0); #endif printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\n"); + +out: + set_fs(old_fs); } /* This is gone through when something in the kernel @@ -538,7 +535,7 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) { - if (!user_mode_vm(regs)) + if (!user_mode(regs)) die(str, regs, err); } @@ -556,7 +553,7 @@ goto trap_signal; } - if (!user_mode(regs)) + if (!user_mode_novm(regs)) goto kernel_trap; trap_signal: { @@ -644,7 +641,7 @@ long error_code) { int cpu = get_cpu(); - struct tss_struct *tss = &per_cpu(init_tss, cpu); + struct tss_struct *tss = &init_tss[cpu]; struct thread_struct *thread = ¤t->thread; /* @@ -680,9 +677,25 @@ if (regs->eflags & VM_MASK) goto gp_in_vm86; - if (!user_mode(regs)) + if (!user_mode_novm(regs)) goto gp_in_kernel; +#ifdef CONFIG_PAX_PAGEEXEC + if (current->mm && (current->mm->pax_flags & MF_PAX_PAGEEXEC)) { + struct mm_struct *mm = current->mm; + unsigned long limit; + + down_write(&mm->mmap_sem); + limit = mm->context.user_cs_limit; + if (limit < TASK_SIZE) { + track_exec_limit(mm, limit, TASK_SIZE, PROT_EXEC); + up_write(&mm->mmap_sem); + return; + } + up_write(&mm->mmap_sem); + } +#endif + current->thread.error_code = error_code; current->thread.trap_no = 13; force_sig(SIGSEGV, current); @@ -698,6 +711,13 @@ if (notify_die(DIE_GPF, "general protection fault", regs, error_code, 13, SIGSEGV) == NOTIFY_STOP) return; + +#ifdef CONFIG_PAX_KERNEXEC + if ((regs->xcs & 0xFFFF) == __KERNEL_CS) + die("PAX: suspicious general protection fault", regs, error_code); + else +#endif + die("general protection fault", regs, error_code); } } @@ -781,7 +801,7 @@ /* If we are in kernel we are probably nested up pretty bad * and might aswell get out now while we still can. */ - if (!user_mode_vm(regs)) { + if (!user_mode(regs)) { current->thread.trap_no = 2; crash_kexec(regs); } @@ -913,7 +933,7 @@ * check for kernel mode by just checking the CPL * of CS. */ - if (!user_mode(regs)) + if (!user_mode_novm(regs)) goto clear_TF_reenable; } @@ -1189,7 +1209,19 @@ */ void set_intr_gate(unsigned int n, void *addr) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + _set_gate(n, DESCTYPE_INT, addr, __KERNEL_CS); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } /*