Skip site navigation (1)Skip section navigation (2)
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>