#include "mach_traps.h"
-asmlinkage int system_call(void);
-asmlinkage void lcall7(void);
-asmlinkage void lcall27(void);
-
-struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
- { 0, 0 }, { 0, 0 } };
+struct desc_struct default_ldt[] __attribute__((__section__(".data.default_ldt"))) = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
+struct page *default_ldt_page;
/* Do we ignore FPU interrupts ? */
char ignore_fpu_irq = 0;
static int kstack_depth_to_print = 24;
-void show_trace(struct task_struct *task, unsigned long * stack)
+static int valid_stack_ptr(struct task_struct *task, void *p)
+{
+ if (p <= (void *)task->thread_info)
+ return 0;
+ if (kstack_end(p))
+ return 0;
+ return 1;
+}
+
+#ifdef CONFIG_FRAME_POINTER
+void print_context_stack(struct task_struct *task, unsigned long *stack,
+ unsigned long ebp)
{
unsigned long addr;
- if (!stack)
- stack = (unsigned long*)&stack;
+ while (valid_stack_ptr(task, (void *)ebp)) {
+ addr = *(unsigned long *)(ebp + 4);
+ printk(" [<%08lx>] ", addr);
+ print_symbol("%s", addr);
+ printk("\n");
+ ebp = *(unsigned long *)ebp;
+ }
+}
+#else
+void print_context_stack(struct task_struct *task, unsigned long *stack,
+ unsigned long ebp)
+{
+ unsigned long addr;
- printk("Call Trace:");
-#ifdef CONFIG_KALLSYMS
- printk("\n");
+ while (!kstack_end(stack)) {
+ addr = *stack++;
+ if (kernel_text_address(addr)) {
+ printk(" [<%08lx>] ", addr);
+ print_symbol("%s\n", addr);
+ }
+ }
+}
#endif
+
+void show_trace(struct task_struct *task, unsigned long * stack)
+{
+ unsigned long ebp;
+
+ if (!task)
+ task = current;
+
+ if (!valid_stack_ptr(task, stack)) {
+ printk("Stack pointer is garbage, not printing trace\n");
+ return;
+ }
+
+ if (task == current) {
+ /* Grab ebp right from our regs */
+ asm ("movl %%ebp, %0" : "=r" (ebp) : );
+ } else {
+ /* ebp is the last reg pushed by switch_to */
+ ebp = *(unsigned long *) task->thread.esp;
+ }
+
while (1) {
struct thread_info *context;
- context = (struct thread_info*) ((unsigned long)stack & (~(THREAD_SIZE - 1)));
- while (!kstack_end(stack)) {
- addr = *stack++;
- if (kernel_text_address(addr)) {
- printk(" [<%08lx>] ", addr);
- print_symbol("%s\n", addr);
- }
- }
+ context = (struct thread_info *)
+ ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+ print_context_stack(task, stack, ebp);
stack = (unsigned long*)context->previous_esp;
if (!stack)
break;
printk("\n ");
printk("%08lx ", *stack++);
}
- printk("\n");
+ printk("\nCall Trace:\n");
show_trace(task, esp);
}
for(i=0;i<20;i++)
{
- unsigned char c;
- if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
+ unsigned char c = 0;
+ if ((user_mode(regs) && get_user(c, &((unsigned char*)regs->eip)[i])) ||
+ (!user_mode(regs) && __direct_get_user(c, &((unsigned char*)regs->eip)[i]))) {
+
bad:
printk(" Bad EIP value.");
break;
eip = regs->eip;
- if (eip < PAGE_OFFSET)
- goto no_bug;
- if (__get_user(ud2, (unsigned short *)eip))
+ if (__direct_get_user(ud2, (unsigned short *)eip))
goto no_bug;
if (ud2 != 0x0b0f)
goto no_bug;
- if (__get_user(line, (unsigned short *)(eip + 2)))
+ if (__direct_get_user(line, (unsigned short *)(eip + 2)))
goto bug;
- if (__get_user(file, (char **)(eip + 4)) ||
- (unsigned long)file < PAGE_OFFSET || __get_user(c, file))
+ if (__direct_get_user(file, (char **)(eip + 4)) ||
+ __direct_get_user(c, file))
file = "<bad filename>";
printk("------------[ cut here ]------------\n");
DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
+/*
+ * the original non-exec stack patch was written by
+ * Solar Designer <solar at openwall.com>. Thanks!
+ */
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
if (regs->eflags & X86_EFLAGS_IF)
if (!(regs->xcs & 3))
goto gp_in_kernel;
+ /*
+ * lazy-check for CS validity on exec-shield binaries:
+ */
+ if (current->mm) {
+ int cpu = smp_processor_id();
+ struct desc_struct *desc1, *desc2;
+ struct vm_area_struct *vma;
+ unsigned long limit = 0;
+
+ spin_lock(¤t->mm->page_table_lock);
+ for (vma = current->mm->mmap; vma; vma = vma->vm_next)
+ if ((vma->vm_flags & VM_EXEC) && (vma->vm_end > limit))
+ limit = vma->vm_end;
+ spin_unlock(¤t->mm->page_table_lock);
+
+ current->mm->context.exec_limit = limit;
+ set_user_cs(¤t->mm->context.user_cs, limit);
+
+ desc1 = ¤t->mm->context.user_cs;
+ desc2 = cpu_gdt_table[cpu] + GDT_ENTRY_DEFAULT_USER_CS;
+
+ /*
+ * The CS was not in sync - reload it and retry the
+ * instruction. If the instruction still faults then
+ * we wont hit this branch next time around.
+ */
+ if (desc1->a != desc2->a || desc1->b != desc2->b) {
+ if (print_fatal_signals >= 2) {
+ printk("#GPF fixup (%ld[seg:%lx]) at %08lx, CPU#%d.\n", error_code, error_code/8, regs->eip, smp_processor_id());
+ printk(" exec_limit: %08lx, user_cs: %08lx/%08lx, CPU_cs: %08lx/%08lx.\n", current->mm->context.exec_limit, desc1->a, desc1->b, desc2->a, desc2->b);
+ }
+ load_user_cs_desc(cpu, current->mm);
+ return;
+ }
+ }
+ if (print_fatal_signals) {
+ printk("#GPF(%ld[seg:%lx]) at %08lx, CPU#%d.\n", error_code, error_code/8, regs->eip, smp_processor_id());
+ printk(" exec_limit: %08lx, user_cs: %08lx/%08lx.\n", current->mm->context.exec_limit, current->mm->context.user_cs.a, current->mm->context.user_cs.b);
+ }
+
current->thread.error_code = error_code;
current->thread.trap_no = 13;
force_sig(SIGSEGV, current);
if (regs->eflags & X86_EFLAGS_IF)
local_irq_enable();
- /* Mask out spurious debug traps due to lazy DR7 setting */
+ /*
+ * Mask out spurious debug traps due to lazy DR7 setting or
+ * due to 4G/4G kernel mode:
+ */
if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
if (!tsk->thread.debugreg[7])
goto clear_dr7;
+ if (!user_mode(regs)) {
+ // restore upon return-to-userspace:
+ set_thread_flag(TIF_DB7);
+ goto clear_dr7;
+ }
}
if (regs->eflags & VM_MASK)
#endif /* CONFIG_MATH_EMULATION */
-#ifdef CONFIG_X86_F00F_BUG
-void __init trap_init_f00f_bug(void)
+void __init trap_init_virtual_IDT(void)
{
- __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
-
/*
- * Update the IDT descriptor and reload the IDT so that
- * it uses the read-only mapped virtual address.
+ * "idt" is magic - it overlaps the idt_descr
+ * variable so that updating idt will automatically
+ * update the idt descriptor..
*/
- idt_descr.address = fix_to_virt(FIX_F00F_IDT);
+ __set_fixmap(FIX_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
+ idt_descr.address = __fix_to_virt(FIX_IDT);
+
__asm__ __volatile__("lidt %0" : : "m" (idt_descr));
}
+
+void __init trap_init_virtual_GDT(void)
+{
+ int cpu = smp_processor_id();
+ struct Xgt_desc_struct *gdt_desc = cpu_gdt_descr + cpu;
+ struct Xgt_desc_struct tmp_desc = {0, 0};
+ struct tss_struct * t;
+
+ __asm__ __volatile__("sgdt %0": "=m" (tmp_desc): :"memory");
+
+#ifdef CONFIG_X86_HIGH_ENTRY
+ if (!cpu) {
+ __set_fixmap(FIX_GDT_0, __pa(cpu_gdt_table), PAGE_KERNEL);
+ __set_fixmap(FIX_GDT_1, __pa(cpu_gdt_table) + PAGE_SIZE, PAGE_KERNEL);
+ __set_fixmap(FIX_TSS_0, __pa(init_tss), PAGE_KERNEL);
+ __set_fixmap(FIX_TSS_1, __pa(init_tss) + 1*PAGE_SIZE, PAGE_KERNEL);
+ __set_fixmap(FIX_TSS_2, __pa(init_tss) + 2*PAGE_SIZE, PAGE_KERNEL);
+ __set_fixmap(FIX_TSS_3, __pa(init_tss) + 3*PAGE_SIZE, PAGE_KERNEL);
+ }
+
+ gdt_desc->address = __fix_to_virt(FIX_GDT_0) + sizeof(cpu_gdt_table[0]) * cpu;
+#else
+ gdt_desc->address = (unsigned long)cpu_gdt_table[cpu];
#endif
+ __asm__ __volatile__("lgdt %0": "=m" (*gdt_desc));
+
+#ifdef CONFIG_X86_HIGH_ENTRY
+ t = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu;
+#else
+ t = init_tss + cpu;
+#endif
+ set_tss_desc(cpu, t);
+ cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
+ load_TR_desc();
+}
#define _set_gate(gate_addr,type,dpl,addr,seg) \
do { \
_set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
}
-static void __init set_trap_gate(unsigned int n, void *addr)
+void __init set_trap_gate(unsigned int n, void *addr)
{
_set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
}
-static void __init set_system_gate(unsigned int n, void *addr)
+void __init set_system_gate(unsigned int n, void *addr)
{
_set_gate(idt_table+n,15,3,addr,__KERNEL_CS);
}
-static void __init set_call_gate(void *a, void *addr)
+void __init set_call_gate(void *a, void *addr)
{
_set_gate(a,12,3,addr,__KERNEL_CS);
}
#ifdef CONFIG_X86_LOCAL_APIC
init_apic_mappings();
#endif
+ init_entry_mappings();
set_trap_gate(0,÷_error);
set_intr_gate(1,&debug);
* default LDT is a single-entry callgate to lcall7 for iBCS
* and a callgate to lcall27 for Solaris/x86 binaries
*/
+#if 0
set_call_gate(&default_ldt[0],lcall7);
set_call_gate(&default_ldt[4],lcall27);
-
+#endif
/*
* Should be a barrier for any external CPU state.
*/