Date: Wed, 26 Nov 1997 23:43:19 -0800 (PST) From: Sean Eric Fagan <sef@kithrup.com> To: security@freebsd.org, hackers@freebsd.org Subject: Updated f00f workaround Message-ID: <199711270743.XAA08912@kithrup.com>
next in thread | raw e-mail | index | archive | help
Well, I was waiting for someone else to do anything about this, but everybody is apparantly busy :). This isn't quite right -- I think there should be a less obviously-i386 method of making the page in question non-writable; there should be a better way to allocate two page-aligned pages of memory; and the check for the fault address should be done lower, but I don't know the code well enough to decide where. Note that these patches are relative to my 2.2-ish source code, but should apply fairly cleanly to any of the distributions. Also note that I don't have anything ifdef'd out just yet, although that'll happen before I check it in. Index: i386/i386/identcpu.c =================================================================== RCS file: /usr/home/sef/CVS-kernel/sys/i386/i386/identcpu.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 identcpu.c --- identcpu.c 1997/03/01 02:57:12 1.1.1.1 +++ identcpu.c 1997/11/27 07:15:00 @@ -78,6 +78,8 @@ { "Pentium Pro", CPUCLASS_686 }, /* CPU_686 */ }; +int has_f00f_bug = 0; + void identifycpu(void) { @@ -105,6 +107,7 @@ break; case 0x500: strcat(cpu_model, "Pentium"); /* nb no space */ + has_f00f_bug = 1; break; case 0x600: strcat(cpu_model, "Pentium Pro"); Index: i386/i386/machdep.c =================================================================== RCS file: /usr/home/sef/CVS-kernel/sys/i386/i386/machdep.c,v retrieving revision 1.2 diff -u -r1.2 machdep.c --- machdep.c 1997/03/01 05:36:35 1.2 +++ machdep.c 1997/11/27 07:39:00 @@ -803,6 +803,10 @@ struct gate_descriptor idt[NIDT]; /* interrupt descriptor table */ union descriptor ldt[NLDT]; /* local descriptor table */ +struct gate_descriptor *t_idt; +unsigned char f00f_idt[PAGE_SIZE * 3]; /* XXX */ +int has_f00f_bug; + static struct i386tss dblfault_tss; static char dblfault_stack[PAGE_SIZE]; @@ -1393,6 +1397,37 @@ /* setup proc 0's pcb */ proc0.p_addr->u_pcb.pcb_flags = 0; proc0.p_addr->u_pcb.pcb_cr3 = IdlePTD; +} + +void f00f_hack(void); +SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL); + +void +f00f_hack(void) { + struct region_descriptor r_idt; + unsigned char *tmp; + int i; + vm_offset_t vp; + unsigned *pte; + + if (!has_f00f_bug) + return; + + printf("Intel Pentium F00F detected, installing workaround\n"); + + r_idt.rd_limit = sizeof(idt) - 1; + + tmp = (unsigned char*)roundup2((unsigned)f00f_idt, PAGE_SIZE); + tmp += PAGE_SIZE - (7 * 8); /* Put 7 entries in lower page */ + t_idt = (struct gate_descriptor*)tmp; + bcopy(idt, t_idt, sizeof(idt)); + r_idt.rd_base = (int)t_idt; + lidt(&r_idt); + vp = trunc_page(t_idt); + pte = (unsigned*)vtopte(vp); + *pte = *pte & ~PG_RW; /* Mark page as non-writable */ + invlpg(vp); + return; } /* Index: i386/i386/trap.c =================================================================== RCS file: /usr/home/sef/CVS-kernel/sys/i386/i386/trap.c,v retrieving revision 1.3 diff -u -r1.3 trap.c --- trap.c 1997/11/24 08:19:19 1.3 +++ trap.c 1997/11/27 07:38:59 @@ -134,6 +134,11 @@ static void userret __P((struct proc *p, struct trapframe *frame, u_quad_t oticks)); +extern struct gate_descriptor *t_idt; +extern int has_f00f_bug; +static int f00f_traps[] = { T_DIVIDE, T_TRCTRAP, T_NMI, T_BPTFLT, + T_OFLOW, T_BOUND, T_PRIVINFLT }; + static inline void userret(p, frame, oticks) struct proc *p; @@ -190,6 +195,7 @@ u_long eva; #endif +restart: type = frame.tf_trapno; code = frame.tf_err; @@ -257,6 +263,8 @@ i = trap_pfault(&frame, TRUE); if (i == -1) return; + if (i == -2) + goto restart; if (i == 0) goto out; @@ -599,6 +607,21 @@ eva = rcr2(); va = trunc_page((vm_offset_t)eva); + + if (has_f00f_bug && + (eva >= (unsigned int)t_idt) && + (eva <= (unsigned int)(((unsigned char*)t_idt) + 7*8))) { + int nr; + + /* + * I think this bit of code should only happen + * on a Pentium with the F00F bug, as nothing else + * should really try to write to the IDT page. + */ + nr = (eva - (unsigned int)t_idt) / 8; + frame->tf_trapno = f00f_traps[nr]; + return -2; + } if (va >= KERNBASE) { /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199711270743.XAA08912>