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>
