Closed Bug 1011859 (CVE-2014-1543) Opened 10 years ago Closed 10 years ago

Heap memory corruption by navigator.getGamepads()

Categories

(Core :: Hardware Abstraction Layer (HAL), defect)

31 Branch
x86_64
Windows 8
defect
Not set
normal

Tracking

()

VERIFIED FIXED
mozilla30
Tracking Status
firefox29 --- wontfix
firefox30 --- verified
firefox31 --- verified
firefox32 --- unaffected
firefox-esr24 --- unaffected
b2g-v1.2 --- unaffected
b2g-v1.3 --- unaffected
b2g-v1.3T --- unaffected
b2g-v1.4 --- fixed
b2g-v2.0 --- unaffected
seamonkey2.26 --- fixed

People

(Reporter: loobenyang, Assigned: ted)

Details

(Keywords: sec-high, Whiteboard: [fixed in 32 by bug 996078][adv-main30+])

Attachments

(5 files)

Attached file reproduction case
User Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36

Steps to reproduce:

Run the attached reproduction case (HeapCorrupt_getGamepads_Repro.html) with firefox debug build.

Reproduction case:

<script>
navigator.getGamepads(); 
</script>

Firefox version:  31.0a1 (2014-04-26), debug build
Operating System:  Windows 8, 64 bit




Actual results:

Windows debug heap reports heap corruptions:

Critical error detected c0000374
firefox.exe has triggered a breakpoint.

First-chance exception at 0x7771AA3C (ntdll.dll) in firefox.exe: 0xC0000374: A heap has been corrupted (parameters: 0x7772FE38).
Unhandled exception at 0x7771AA3C (ntdll.dll) in firefox.exe: 0xC0000374: A heap has been corrupted (parameters: 0x7772FE38).


Stack Trace:

 	ntdll.dll!_RtlReportCriticalFailure@8()	Unknown
 	ntdll.dll!_RtlpReportHeapFailure@4()	Unknown
 	ntdll.dll!_RtlpLogHeapFailure@24()	Unknown
 	ntdll.dll!@RtlpLowFragHeapAllocFromContext@16()	Unknown
 	ntdll.dll!_RtlAllocateHeap@12()	Unknown
 	msvcr120.dll!malloc(unsigned int size) Line 92	C
>	mozalloc.dll!moz_xmalloc(unsigned int size) Line 52	C++
 	xul.dll!nsTArray_base<nsTArrayInfallibleAllocator,nsTArray_CopyWithMemutils>::EnsureCapacity(unsigned int capacity, unsigned int elemSize) Line 119	C++
 	xul.dll!mozilla::dom::Gamepad::Gamepad(nsISupports * aParent, const nsAString_internal & aID, unsigned int aIndex, mozilla::dom::GamepadMappingType aMapping, unsigned int aNumButtons, unsigned int aNumAxes) Line 36	C++
 	xul.dll!mozilla::dom::Gamepad::Clone(nsISupports * aParent) Line 101	C++
 	xul.dll!mozilla::dom::GamepadService::SetWindowHasSeenGamepad(nsGlobalWindow * aWindow, unsigned int aIndex, bool aHasSeen) Line 457	C++
 	xul.dll!mozilla::dom::GamepadService::NewAxisMoveEvent(unsigned int aIndex, unsigned int aAxis, double aValue) Line 287	C++
 	xul.dll!`anonymous namespace'::GamepadEvent::Run() Line 278	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate * aDelegate) Line 136	C++
 	xul.dll!MessageLoop::RunHandler() Line 223	C++
 	xul.dll!MessageLoop::Run() Line 197	C++
 	xul.dll!nsBaseAppShell::Run() Line 166	C++
 	xul.dll!nsAppShell::Run() Line 188	C++
 	xul.dll!nsAppStartup::Run() Line 279	C++
 	xul.dll!XREMain::XRE_mainRun() Line 4019	C++
 	xul.dll!NS_TableDrivenQI(void * aThis, const nsID & aIID, void * * aInstancePtr, const QITableEntry * entries) Line 17	C++
 	xul.dll!nsComponentManagerImpl::QueryInterface(const nsID & aIID, void * * aInstancePtr) Line 823	C++
 	xul.dll!nsQueryInterface::operator()(const nsID & aIID, void * * answer) Line 19	C++
 	xul.dll!nsCOMPtr_base::assign_from_qi(const nsQueryInterface qi, const nsID & iid) Line 56	C++




Registers:

EAX = 001DF37C EBX = 157EAEB0 ECX = 00000001 EDX = 001DF211 ESI = 00000005 EDI = 11161484 EIP = 60BD1412 ESP = 001DF550 EBP = 00000008 EFL = 00000000 


Expected results:

No heap corruption should happen.
In this case, the memory corruption was not reported at the first time of illegal memory write. So I got a couple different stack traces when the buffer overflow or corruption was reported. A few of them:


1)

HEAP[firefox.exe]: Heap block at 0B1B0A40 modified at 0B1B0A78 past requested size of 30
firefox.exe has triggered a breakpoint.

The thread 0x2270 has exited with code 0 (0x0).
HEAP[firefox.exe]: Invalid address specified to RtlFreeHeap( 010F0000, 0B1B0A48 )
firefox.exe has triggered a breakpoint.
 	ntdll.dll!_RtlpBreakPointHeap@4()	Unknown
 	ntdll.dll!_RtlpCheckBusyBlockTail@8()	Unknown
 	ntdll.dll!_RtlpValidateHeapEntry@12()	Unknown
 	ntdll.dll!_RtlDebugFreeHeap@12()	Unknown
 	ntdll.dll!@RtlpFreeHeap@16()	Unknown
 	ntdll.dll!_RtlFreeHeap@12()	Unknown
 	msvcr120.dll!free(void * pBlock) Line 51	C
 	xul.dll!nsTArray_base<nsTArrayInfallibleAllocator,nsTArray_CopyWithMemutils>::ShrinkCapacity(unsigned int elemSize, unsigned int elemAlign) Line 210	C++
 	xul.dll!nsTArray_base<nsTArrayInfallibleAllocator,nsTArray_CopyWithMemutils>::ShiftData(unsigned int start, unsigned int oldLen, unsigned int newLen, unsigned int elemSize, unsigned int elemAlign) Line 238	C++
>	xul.dll!nsTArray_Impl<unsigned __int64,nsTArrayInfallibleAllocator>::~nsTArray_Impl<unsigned __int64,nsTArrayInfallibleAllocator>() Line 764	C++
 	xul.dll!mozilla::dom::Gamepad::~Gamepad() Line 90	C++
 	[External Code]	
 	xul.dll!nsDOMCaretPosition::DeleteCycleCollectable() Line 69	C++
 	xul.dll!mozilla::dom::DOMError::cycleCollection::DeleteCycleCollectable(void * p) Line 33	C++
 	xul.dll!SnowWhiteKiller::~SnowWhiteKiller() Line 2397	C++
 	xul.dll!nsPurpleBuffer::RemoveSkippable(nsCycleCollector * aCollector, bool aRemoveChildlessNodes, bool aAsyncSnowWhiteFreeing, void (void) * aCb) Line 2546	C++
 	xul.dll!nsCycleCollector::ForgetSkippable(bool aRemoveChildlessNodes, bool aAsyncSnowWhiteFreeing) Line 2588	C++
 	xul.dll!nsCycleCollector_forgetSkippable(bool aRemoveChildlessNodes, bool aAsyncSnowWhiteFreeing) Line 3822	C++
 	xul.dll!FireForgetSkippable(unsigned int aSuspected, bool aRemoveChildless) Line 1776	C++
 	xul.dll!CCTimerFired(nsITimer * aTimer, void * aClosure) Line 2277	C++
 	xul.dll!nsTimerImpl::Fire() Line 555	C++
 	xul.dll!nsTimerEvent::Run() Line 641	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate * aDelegate) Line 136	C++
 	xul.dll!MessageLoop::RunHandler() Line 223	C++
 	xul.dll!MessageLoop::Run() Line 197	C++
 	xul.dll!nsBaseAppShell::Run() Line 166	C++
 	xul.dll!nsAppShell::Run() Line 188	C++
 	xul.dll!nsAppStartup::Run() Line 279	C++
 	xul.dll!XREMain::XRE_mainRun() Line 4019	C++
 	xul.dll!NS_TableDrivenQI(void * aThis, const nsID & aIID, void * * aInstancePtr, const QITableEntry * entries) Line 17	C++
 	xul.dll!nsComponentManagerImpl::QueryInterface(const nsID & aIID, void * * aInstancePtr) Line 823	C++
 	xul.dll!nsQueryInterface::operator()(const nsID & aIID, void * * answer) Line 19	C++
 	xul.dll!nsCOMPtr_base::assign_from_qi(const nsQueryInterface qi, const nsID & iid) Line 56	C++








2)

Critical error detected c0000374
firefox.exe has triggered a breakpoint.

First-chance exception at 0x77F4AA3C (ntdll.dll) in firefox.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77F5FE38).
Unhandled exception at 0x77F4AA3C (ntdll.dll) in firefox.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77F5FE38).




 	ntdll.dll!_RtlReportCriticalFailure@8()	Unknown
 	ntdll.dll!_RtlpReportHeapFailure@4()	Unknown
 	ntdll.dll!_RtlpLogHeapFailure@24()	Unknown
 	ntdll.dll!@RtlpLowFragHeapAllocFromContext@16()	Unknown
 	ntdll.dll!_RtlAllocateHeap@12()	Unknown
 	msvcr120.dll!malloc(unsigned int size) Line 92	C
 	mozalloc.dll!moz_xmalloc(unsigned int size) Line 52	C++
>	xul.dll!mozilla::dom::GamepadEvent::Constructor(mozilla::dom::EventTarget * aOwner, const nsAString_internal & aType, const mozilla::dom::GamepadEventInit & aEventInitDict) Line 66	C++
 	xul.dll!mozilla::dom::GamepadService::FireConnectionEvent(mozilla::dom::EventTarget * aTarget, mozilla::dom::Gamepad * aGamepad, bool aConnected) Line 396	C++
 	xul.dll!mozilla::dom::GamepadService::NewAxisMoveEvent(unsigned int aIndex, unsigned int aAxis, double aValue) Line 296	C++
 	xul.dll!`anonymous namespace'::GamepadEvent::Run() Line 278	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate * aDelegate) Line 95	C++
 	xul.dll!MessageLoop::RunHandler() Line 223	C++
 	xul.dll!MessageLoop::Run() Line 197	C++
 	xul.dll!nsBaseAppShell::Run() Line 166	C++
 	xul.dll!nsAppShell::Run() Line 188	C++
 	xul.dll!nsAppStartup::Run() Line 279	C++
 	xul.dll!XREMain::XRE_mainRun() Line 4019	C++
 	xul.dll!NS_TableDrivenQI(void * aThis, const nsID & aIID, void * * aInstancePtr, const QITableEntry * entries) Line 17	C++
 	xul.dll!nsComponentManagerImpl::QueryInterface(const nsID & aIID, void * * aInstancePtr) Line 823	C++
 	xul.dll!nsQueryInterface::operator()(const nsID & aIID, void * * answer) Line 19	C++
 	xul.dll!nsCOMPtr_base::assign_from_qi(const nsQueryInterface qi, const nsID & iid) Line 56	C++




3)

Critical error detected c0000374
firefox.exe has triggered a breakpoint.

First-chance exception at 0x77F4AA3C (ntdll.dll) in firefox.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77F5FE38).
Unhandled exception at 0x77F4AA3C (ntdll.dll) in firefox.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77F5FE38).



 	ntdll.dll!_RtlReportCriticalFailure@8()	Unknown
 	ntdll.dll!_RtlpReportHeapFailure@4()	Unknown
 	ntdll.dll!_RtlpLogHeapFailure@24()	Unknown
 	ntdll.dll!@RtlpLowFragHeapAllocFromContext@16()	Unknown
 	ntdll.dll!_RtlAllocateHeap@12()	Unknown
 	msvcr120.dll!malloc(unsigned int size) Line 92	C
>	mozalloc.dll!moz_xmalloc(unsigned int size) Line 52	C++
 	xul.dll!XPCConvert::JSData2Native(void * d, JS::Handle<JS::Value> s, const nsXPTType & type, bool useAllocator, const nsID * iid, tag_nsresult * pErr) Line 573	C++
 	xul.dll!XPCWrappedNative::CallMethod(XPCCallContext & ccx, XPCWrappedNative::CallMode mode) Line 1700	C++
 	xul.dll!XPC_WN_CallMethod(JSContext * cx, unsigned int argc, JS::Value * vp) Line 1285	C++
 	mozjs.dll!js::Invoke(JSContext * cx, JS::CallArgs args, js::MaybeConstruct construct) Line 467	C++
 	mozjs.dll!Interpret(JSContext * cx, js::RunState & state) Line 2621	C++
 	mozjs.dll!js::RunScript(JSContext * cx, js::RunState & state) Line 421	C++
 	mozjs.dll!js::Invoke(JSContext * cx, JS::CallArgs args, js::MaybeConstruct construct) Line 496	C++
 	mozjs.dll!js::Invoke(JSContext * cx, const JS::Value & thisv, const JS::Value & fval, unsigned int argc, const JS::Value * argv, JS::MutableHandle<JS::Value> rval) Line 530	C++
 	mozjs.dll!js::DirectProxyHandler::call(JSContext * cx, JS::Handle<JSObject *> proxy, const JS::CallArgs & args) Line 465	C++
 	mozjs.dll!js::CrossCompartmentWrapper::call(JSContext * cx, JS::Handle<JSObject *> wrapper, const JS::CallArgs & args) Line 465	C++
 	mozjs.dll!js::Proxy::call(JSContext * cx, JS::Handle<JSObject *> proxy, const JS::CallArgs & args) Line 2686	C++
 	mozjs.dll!js::proxy_Call(JSContext * cx, unsigned int argc, JS::Value * vp) Line 3089	C++
 	mozjs.dll!js::Invoke(JSContext * cx, JS::CallArgs args, js::MaybeConstruct construct) Line 467	C++
 	mozjs.dll!Interpret(JSContext * cx, js::RunState & state) Line 2621	C++
 	mozjs.dll!js::RunScript(JSContext * cx, js::RunState & state) Line 421	C++
 	mozjs.dll!js::Invoke(JSContext * cx, JS::CallArgs args, js::MaybeConstruct construct) Line 496	C++
 	mozjs.dll!Interpret(JSContext * cx, js::RunState & state) Line 2621	C++
 	mozjs.dll!js::RunScript(JSContext * cx, js::RunState & state) Line 421	C++
 	mozjs.dll!js::Invoke(JSContext * cx, JS::CallArgs args, js::MaybeConstruct construct) Line 496	C++
 	mozjs.dll!js::Invoke(JSContext * cx, const JS::Value & thisv, const JS::Value & fval, unsigned int argc, const JS::Value * argv, JS::MutableHandle<JS::Value> rval) Line 530	C++
 	mozjs.dll!js::jit::DoCallFallback(JSContext * cx, js::jit::BaselineFrame * frame, js::jit::ICCall_Fallback * stub_, unsigned int argc, JS::Value * vp, JS::MutableHandle<JS::Value> res) Line 8251	C++
 	[External Code]	
 	[Frames below may be incorrect and/or missing]	
 	mozjs.dll!EnterBaseline(JSContext * cx, js::jit::EnterJitData & data) Line 128	C++
 	mozjs.dll!js::jit::EnterBaselineMethod(JSContext * cx, js::RunState & state) Line 157	C++
 	mozjs.dll!Interpret(JSContext * cx, js::RunState & state) Line 2660	C++
 	mozjs.dll!js::RunScript(JSContext * cx, js::RunState & state) Line 421	C++
 	mozjs.dll!js::Invoke(JSContext * cx, JS::CallArgs args, js::MaybeConstruct construct) Line 496	C++
 	mozjs.dll!js_fun_apply(JSContext * cx, unsigned int argc, JS::Value * vp) Line 1021	C++
 	mozjs.dll!js::Invoke(JSContext * cx, JS::CallArgs args, js::MaybeConstruct construct) Line 467	C++
 	mozjs.dll!js::Invoke(JSContext * cx, const JS::Value & thisv, const JS::Value & fval, unsigned int argc, const JS::Value * argv, JS::MutableHandle<JS::Value> rval) Line 530	C++
 	mozjs.dll!js::DirectProxyHandler::call(JSContext * cx, JS::Handle<JSObject *> proxy, const JS::CallArgs & args) Line 465	C++
 	mozjs.dll!js::CrossCompartmentWrapper::call(JSContext * cx, JS::Handle<JSObject *> wrapper, const JS::CallArgs & args) Line 465	C++
 	mozjs.dll!js::Proxy::call(JSContext * cx, JS::Handle<JSObject *> proxy, const JS::CallArgs & args) Line 2686	C++
 	mozjs.dll!js::proxy_Call(JSContext * cx, unsigned int argc, JS::Value * vp) Line 3089	C++
 	mozjs.dll!js::Invoke(JSContext * cx, JS::CallArgs args, js::MaybeConstruct construct) Line 467	C++
 	mozjs.dll!Interpret(JSContext * cx, js::RunState & state) Line 2621	C++
 	mozjs.dll!js::RunScript(JSContext * cx, js::RunState & state) Line 421	C++
 	mozjs.dll!js::Invoke(JSContext * cx, JS::CallArgs args, js::MaybeConstruct construct) Line 496	C++
 	mozjs.dll!js::Invoke(JSContext * cx, const JS::Value & thisv, const JS::Value & fval, unsigned int argc, const JS::Value * argv, JS::MutableHandle<JS::Value> rval) Line 530	C++
 	mozjs.dll!JS_CallFunctionValue(JSContext * cx, JS::Handle<JSObject *> obj, JS::Handle<JS::Value> fval, const JS::HandleValueArray & args, JS::MutableHandle<JS::Value> rval) Line 5099	C++
 	xul.dll!nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS * wrapper, unsigned short methodIndex, const XPTMethodDescriptor * info_, nsXPTCMiniVariant * nativeParams) Line 1274	C++
 	xul.dll!nsXPCWrappedJS::CallMethod(unsigned short methodIndex, const XPTMethodDescriptor * info, nsXPTCMiniVariant * params) Line 518	C++
 	xul.dll!PrepareAndDispatch(nsXPTCStubBase * self, unsigned int methodIndex, unsigned int * args, unsigned int * stackBytesToPop) Line 85	C++
 	xul.dll!SharedStub() Line 113	C++
 	xul.dll!nsTimerImpl::Fire() Line 558	C++
 	xul.dll!nsTimerEvent::Run() Line 641	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate * aDelegate) Line 136	C++
 	xul.dll!MessageLoop::RunHandler() Line 223	C++
 	xul.dll!MessageLoop::Run() Line 197	C++
 	xul.dll!nsBaseAppShell::Run() Line 166	C++
 	xul.dll!nsAppShell::Run() Line 188	C++
 	xul.dll!nsAppStartup::Run() Line 279	C++
 	xul.dll!XREMain::XRE_mainRun() Line 4019	C++
 	xul.dll!NS_TableDrivenQI(void * aThis, const nsID & aIID, void * * aInstancePtr, const QITableEntry * entries) Line 17	C++
 	xul.dll!nsComponentManagerImpl::QueryInterface(const nsID & aIID, void * * aInstancePtr) Line 823	C++
 	xul.dll!nsQueryInterface::operator()(const nsID & aIID, void * * answer) Line 19	C++
 	xul.dll!nsCOMPtr_base::assign_from_qi(const nsQueryInterface qi, const nsID & iid) Line 56	C++
Component: Untriaged → DOM: Device Interfaces
Product: Firefox → Core
Summary: Security: Heap memory corruption by navigator.getGamepads() → Heap memory corruption by navigator.getGamepads()
(In reply to Looben from comment #0)
> Created attachment 8424311 [details]
> reproduction case
> 
> User Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML,
> like Gecko) Chrome/34.0.1847.137 Safari/537.36
> 
> Steps to reproduce:
> 
> Run the attached reproduction case (HeapCorrupt_getGamepads_Repro.html) with
> firefox debug build.
> 

To clarify, you must have attached a gamepad and provided some input to it, correct? Otherwise you wouldn't be seeing the GamepadEvent::Run() and GamepadService::NewAxisMoveEvent on the stack.
Windows 8 laptop with default configuration has gamepad device.
To reproduce it with Windows 7 or lower, probably you can install a vJoy driver.

No physical gamepad device is attached. And this gamepad relevant code only run once on the initial discovery of gamepads. Simply open a new tab again and load the test case doesn't hit the code. To trigger it again the Firefox browser needs restart.
After enabling page heap (gflags.exe /p /enable firefox.exe /full), which inserts inaccessible memory page after each heap buffer, the first buffer overflow was caught. I got:


Unhandled exception at 0x0FB2759D (xul.dll) in firefox.exe: 0xC0000005: Access violation reading location 0xABA8F000.

Faulty code:

   Gamepad::SetAxis(uint32_t aAxis, double aValue)
   {
     MOZ_ASSERT(aAxis < mAxes.Length());
-->  if (mAxes[aAxis] != aValue) {
-->    mAxes[aAxis] = aValue;
       GamepadBinding::ClearCachedAxesValue(this);
     }
   }


Stack Trace:

>	xul.dll!mozilla::dom::Gamepad::SetAxis(unsigned int aAxis, double aValue) Line 67	C++
 	xul.dll!mozilla::dom::GamepadService::NewAxisMoveEvent(unsigned int aIndex, unsigned int aAxis, double aValue) Line 271	C++
 	xul.dll!`anonymous namespace'::GamepadEvent::Run() Line 278	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate * aDelegate) Line 95	C++
 	xul.dll!MessageLoop::RunHandler() Line 223	C++
 	xul.dll!MessageLoop::Run() Line 197	C++
 	xul.dll!nsBaseAppShell::Run() Line 166	C++
 	xul.dll!nsAppShell::Run() Line 188	C++
 	xul.dll!nsAppStartup::Run() Line 279	C++
 	xul.dll!XREMain::XRE_mainRun() Line 4019	C++
 	xul.dll!NS_TableDrivenQI(void * aThis, const nsID & aIID, void * * aInstancePtr, const QITableEntry * entries) Line 17	C++
 	xul.dll!nsComponentManagerImpl::QueryInterface(const nsID & aIID, void * * aInstancePtr) Line 823	C++
 	xul.dll!nsQueryInterface::operator()(const nsID & aIID, void * * answer) Line 19	C++
 	xul.dll!nsCOMPtr_base::assign_from_qi(const nsQueryInterface qi, const nsID & iid) Line 56	C++

	
Registers:

	EAX = 00000000 EBX = 0B7F8F98 ECX = B073FFC0 EDX = ABA8EFD0 ESI = 00000005 EDI = 2E219FD8 EIP = 0FB2759D ESP = 0023F964 EBP = 00000009 EFL = 00210287 


Memory:

	0xABA8EFD0  05 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0  ......................................ð
	0xABA8EFF7  bf 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??  ¿......................................
	0xABA8F01E  ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??  .......................................
	0xABA8F045  ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??  .......................................


Possible Fix:

	One possible fix is to add boundry check for mAxes[aAxis] in Gamepad::SetAxis(), which can prevent the heap corruption caused by this test case or maybe some other twisted variant.
This vulnerability affects current Firefox release 29.0.1.

I run the test case with official 29.0.1 build, the browser crashed with virtual table pointer corrupted. I'll attach the full stack trace and windbg crash report in text files for easy reading.



Stack Trace:

00f0f6b8 0f8cd627 00f0f744 02c8d7e4 084e30d4 xul!CanonicalizeXPCOMParticipant+0xd
00f0f6c8 0f8cd71f 00f0f700 00f0f70c 00000855 xul!CanonicalizeParticipant+0x17
00f0f744 0f7812b6 00000000 00f0f700 60f310c0 xul!nsCycleCollector::ForgetSkippable+0x9f
00f0f75c 0f9a4d65 00000000 00f0f700 00001770 xul!nsCycleCollector_forgetSkippable+0x3b
00f0f784 0f9a4e89 00000000 07abec80 0f9a4e07 xul!FireForgetSkippable+0x39
00f0f7ac 0f9560b7 07abec80 00000000 02c15240 xul!CCTimerFired+0x82
00f0f7c8 0f956234 0f8be009 086af070 02c0e9b0 xul!nsTimerImpl::Fire+0xc7
00f0f7cc 0f8be009 086af070 02c0e9b0 02c20280 xul!nsTimerEvent::Run+0x14
00f0f848 0f8a5e2d 02c15201 00000001 00f0f860 xul!nsThread::ProcessNextEvent+0x2c9
00f0f858 0faaf522 02c15201 00000001 02c20280 xul!NS_ProcessNextEvent+0x2d
00f0f884 0faa4251 00c20280 87a9227e 02c15240 xul!mozilla::ipc::MessagePump::Run+0x9b
00f0f8bc 0faa431b 02c15be0 00000001 00f0f900 xul!MessageLoop::RunHandler+0x51
00f0f8dc 0fa08540 80000000 0715b140 0fa0afbf xul!MessageLoop::Run+0x19
00f0f8e8 0fa0afbf 02c15be0 0ffb4613 02c15be0 xul!nsBaseAppShell::Run+0x2c
00f0f8fc 0f99cb9a 0715b140 62321087 00f0fa10 xul!nsAppShell::Run+0x14
00f0f9d0 0f9f2eda 00f0fa10 00f0fb38 00f0fa10 xul!XREMain::XRE_mainRun+0x44f
00f0f9f0 0fa2153c 00f0fa10 00000000 010768a0 xul!XREMain::XRE_main+0xe3
00f0fb08 013216dd 00000001 010768a0 00f0fb38 xul!XRE_main+0x30
00f0fc9c 013219a2 00000001 010768a0 02c18160 firefox!do_main+0x283
00f0fd30 01321aad 00000001 010768a0 00000000 firefox!NS_internal_main+0x11d
00f0fd64 0132237b 00000000 01071320 01077e70 firefox!wmain+0xf0
00f0fda8 758386e3 ff27e000 00f0fdf8 7765bf39 firefox!__tmainCRTStartup+0x122
00f0fdb4 7765bf39 ff27e000 e5f947df 00000000 KERNEL32!BaseThreadInitThunk+0xe
00f0fdf8 7765bf0c 0132249c ff27e000 ffffffff ntdll!__RtlUserThreadStart+0x72
00f0fe10 00000000 0132249c ff27e000 00000000 ntdll!_RtlUserThreadStart+0x1b


Registers:

eax=08232c10 ebx=00f0f70c ecx=00000000 edx=00f0f6b8 esi=02c8d7e4 edi=00f0f700
eip=0f8cd65d esp=00f0f6ac ebp=00f0f75c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246


Locals:


in	0x08232c10 class nsISupports *
 __vfptr	0x00000000 
  [0]	<Memory access error>
  [1]	<Memory access error>
  [2]	<Memory access error>
out	0x00f0f700 class nsISupports *
 __vfptr	0x08232c10 
  [0]	0x00000000 
  [1]	0xbff00000 
  [2]	0x00000000 
  

Firefox version: 29.0.1
OS: Windows 8 64bit
Attached file 29.01_vfptr0_stack
Attached file 29.01_vfptr0_registers
(In reply to Looben from comment #3)
> Windows 8 laptop with default configuration has gamepad device.
> To reproduce it with Windows 7 or lower, probably you can install a vJoy
> driver.

Can you point me at some information about this laptop? That's the first I've ever heard of a laptop with a built-in gamepad device. It's possible that it's something specific to this hardware configuration that trips this bug. I have a pile of gamepads here I've tested with and haven't seen this behavior.

Can you test against a recent Nightly build? The Windows Gamepad backend was rewritten in bug 996078 which may have fixed this as a side effect.
(In reply to Ted Mielczarek [:ted.mielczarek] from comment #9)
> (In reply to Looben from comment #3)
> > Windows 8 laptop with default configuration has gamepad device.
> > To reproduce it with Windows 7 or lower, probably you can install a vJoy
> > driver.
> 
> Can you point me at some information about this laptop? That's the first
> I've ever heard of a laptop with a built-in gamepad device. It's possible
> that it's something specific to this hardware configuration that trips this
> bug. I have a pile of gamepads here I've tested with and haven't seen this
> behavior.
> 
> Can you test against a recent Nightly build? The Windows Gamepad backend was
> rewritten in bug 996078 which may have fixed this as a side effect.


If I remember correctly, there is a "Microsoft Input Configuration Device" registered as gamepad device.

Probably you need a vJoy driver to produce. 
I reproduce this bug in Windows 8 laptop and Windows 7 workstation, but both of them have vJoy driver installed. Just have the virtual driver installed, I did not launch the vJoy application or feed any input to it.
I updated my local repository to latest, then windows debug heap did not detect any heap corruption when running this test case. 

Analyzing the code, it may be influenced by the changes of WindowsGamepad.cpp for bug 996078.
Looks like this vulnerability with this test case only affects the builds before the code for bug 996078 was landed.

Probably you don't need to do any change at the moment but just waiting for users to upgrade to future releases.
However,  to defense against any other possible script variant, you may still consider adding the boundary check for mAxes[aAxis] in Gamepad::SetAxis().
Ted: so Nightly is fixed, but users since Firefox 24/28 are potentially at risk. I'd imagine you're not too keen to accelerate the landing of bug 996078 but is there part of it that we can pull forward? How common is the vJoy driver, do we need to talk to them about it or was the bug solely on our side?
Flags: needinfo?(ted)
I would be happy to branch-land that patch, I think it's a measurable improvement in the code. Then again, it is pretty invasive, so I'm not sure how happy release management would be about that.

I don't know how common that driver is, and I'm not sure. It could be simply exposing a bug in our code. From comment 4 it sounds like we might be able to band-aid this pretty easily. I'll whip up a patch for that tomorrow.
Assignee: nobody → ted
Flags: needinfo?(ted)
After installing vJoy and fiddling with it, I think I've figured out the root cause, and it should be a small patch. The problem is here:
https://hg.mozilla.org/releases/mozilla-aurora/annotate/e16b9c26e3fa/hal/windows/WindowsGamepad.cpp#l589

Devices can present non-contiguous axes--this is easy to do with vJoy, just use the "Configure vJoy" tool and uncheck Y or Z and hit Ok. The code assumes that the axes are 0..numAxes, but the axis indices may actually be higher than numAxes because of missing entries.

It's possible this bug could be exposed by real hardware that has this configuration (I'd have to check my collection of devices to see if any of them do that, but it wouldn't surprise me). On the plus side, the rewrite that's in Nightly doesn't suffer this bug.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Well, that sounds like it would be hard to exploit given the requirement for weird hardware, but bad when it happens, so I'll mark it high.
Component: DOM: Device Interfaces → Hardware Abstraction Layer (HAL)
Keywords: sec-high
Whiteboard: [fixed in 32 by bug 996078]
This is slightly more complicated than I wanted because DirectInput has a stupid API. When we first enumerate the axes on a gamepad we need to save each one in the axes array so we can look them back up and get the proper index when we receive data. Unfortunately the struct you get while enumerating axes apparently doesn't have the same data as the struct you get when receiving data, so I have to loop through the entries of "c_dfDIJoystick" which defines the data format we're using to find the matching bits.

Since we don't really have any HAL peers I'm tagging smaug since I've made him review a bunch of other Gamepad patches.
Attachment #8426294 - Flags: review?(bugs)
I don't think either of them have ever looked at any of this code, I believe Bas reviewed this code originally.
Comment on attachment 8426294 [details] [diff] [review]
Order gamepad axes properly

This is too Windows-y for me to review.
Attachment #8426294 - Flags: review?(bugs)
Comment on attachment 8426294 [details] [diff] [review]
Order gamepad axes properly

Okay, thanks for looking.

Jim: can you review this code? You reviewed the patch where I replaced this all on m-c, but we need to fix this bug on Aurora/Beta.
Attachment #8426294 - Flags: review?(jmathies)
Comment on attachment 8426294 [details] [diff] [review]
Order gamepad axes properly

Review of attachment 8426294 [details] [diff] [review]:
-----------------------------------------------------------------

This looks ok to me, basically walk the list of objects the device support looking axis and cache that in our own list, which we then iterate over.

::: hal/windows/WindowsGamepad.cpp
@@ +396,5 @@
>    gamepad->device->SetProperty(DIPROP_RANGE, &dp.diph);
> +  // Find what the dwOfs of this object in the c_dfDIJoystick data format is.
> +  for (DWORD i = 0; i < c_dfDIJoystick.dwNumObjs; i++) {
> +    if (c_dfDIJoystick.rgodf[i].pguid &&
> +        IsEqualGUID(*c_dfDIJoystick.rgodf[i].pguid, lpddoi->guidType) &&

Not sure I understand this check but I assume you do, what's in lpddoi->guidType? I would have expected some sort of constant here.
Attachment #8426294 - Flags: review?(jmathies) → review+
It's a GUID, lpddoi is a pointer to one of these:
http://msdn.microsoft.com/en-us/library/microsoft.directx_sdk.reference.dideviceobjectinstance.ASPX

I could probably write out a big table of known GUIDs to offsets, but that's essentially what c_dfDIJoystick is, so I thought it made sense to just use it.
Try build:
https://tbpl.mozilla.org/?tree=Try&rev=5a45efd2b1d5

Looben: if you'd like to test this patch locally I'd appreciate it. I believe it fixes the reported issue.
Comment on attachment 8426294 [details] [diff] [review]
Order gamepad axes properly

[Approval Request Comment]
Bug caused by (feature/regressing bug #): Existing defect in Gamepad API shipped in Firefox 29.
User impact if declined: Heap corruption with certain hardware or certain configurations of the vJoy driver.
Testing completed (on m-c, etc.): Manual testing completed locally with vJoy driver. patch is Aurora/Beta only as this code has been rewritten in m-c.
Risk to taking this patch (and alternatives if risky): Minimal risk.
String or IDL/UUID changes made by this patch: N/A
Attachment #8426294 - Flags: approval-mozilla-beta?
Attachment #8426294 - Flags: approval-mozilla-aurora?
(In reply to Ted Mielczarek [:ted.mielczarek] from comment #23)
> Try build:
> https://tbpl.mozilla.org/?tree=Try&rev=5a45efd2b1d5
> 
> Looben: if you'd like to test this patch locally I'd appreciate it. I
> believe it fixes the reported issue.

I replaced my local WindowsGamepad.cpp with this version https://hg.mozilla.org/try/raw-file/5a45efd2b1d5/hal/windows/WindowsGamepad.cpp and built. I did not see the reported issue.

Good job Ted.
Thanks for testing, and thanks for the bug report!
(In reply to Ted Mielczarek [:ted.mielczarek] from comment #26)
> Thanks for testing, and thanks for the bug report!

Hang on. 
I did not observe the reported issue as before.

However, I can see the buffer overflow at the same place if I place some break points in the code. Looks like the buffer overflow can still occur under some race condition. Does the patch has some dependency on time sequence?

I enable page heap to catch the overrun. The stack seems weird, like loop:


>	xul.dll!mozilla::dom::Gamepad::SetAxis(unsigned int aAxis, double aValue) Line 67	C++
 	xul.dll!mozilla::dom::GamepadService::NewAxisMoveEvent(unsigned int aIndex, unsigned int aAxis, double aValue) Line 271	C++
 	xul.dll!`anonymous namespace'::GamepadEvent::Run() Line 280	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!nsThread::Shutdown() Line 559	C++
 	xul.dll!nsRunnableMethodImpl<enum tag_nsresult (__stdcall nsIUrlClassifierDBServiceWorker::*)(void),void,1>::Run() Line 388	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!nsThread::Shutdown() Line 559	C++
 	xul.dll!nsRunnableMethodImpl<enum tag_nsresult (__stdcall nsIUrlClassifierDBServiceWorker::*)(void),void,1>::Run() Line 388	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!nsThread::Shutdown() Line 559	C++
 	xul.dll!nsRunnableMethodImpl<enum tag_nsresult (__stdcall nsIUrlClassifierDBServiceWorker::*)(void),void,1>::Run() Line 388	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!nsThread::Shutdown() Line 559	C++
 	xul.dll!nsRunnableMethodImpl<enum tag_nsresult (__stdcall nsIUrlClassifierDBServiceWorker::*)(void),void,1>::Run() Line 388	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!nsThread::Shutdown() Line 559	C++
 	xul.dll!nsRunnableMethodImpl<enum tag_nsresult (__stdcall nsIUrlClassifierDBServiceWorker::*)(void),void,1>::Run() Line 388	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!nsThread::Shutdown() Line 559	C++
 	xul.dll!nsRunnableMethodImpl<enum tag_nsresult (__stdcall nsIUrlClassifierDBServiceWorker::*)(void),void,1>::Run() Line 388	C++
 	xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) Line 715	C++
 	xul.dll!NS_ProcessNextEvent(nsIThread * thread, bool mayWait) Line 263	C++
 	xul.dll!mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate * aDelegate) Line 95	C++
 	xul.dll!MessageLoop::RunHandler() Line 223	C++
 	xul.dll!MessageLoop::Run() Line 197	C++
 	xul.dll!nsBaseAppShell::Run() Line 166	C++
 	xul.dll!nsAppShell::Run() Line 188	C++
 	xul.dll!nsAppStartup::Run() Line 279	C++
 	xul.dll!XREMain::XRE_mainRun() Line 4019	C++
 	xul.dll!NS_TableDrivenQI(void * aThis, const nsID & aIID, void * * aInstancePtr, const QITableEntry * entries) Line 17	C++
 	xul.dll!nsComponentManagerImpl::QueryInterface(const nsID & aIID, void * * aInstancePtr) Line 823	C++
 	xul.dll!nsQueryInterface::operator()(const nsID & aIID, void * * answer) Line 19	C++
 	xul.dll!nsCOMPtr_base::assign_from_qi(const nsQueryInterface qi, const nsID & iid) Line 56	C++



Registers:

EAX = 00000000 EBX = 0B770F98 ECX = 9F726FC0 EDX = 9FB8AFD8 ESI = 00000004 EDI = 9B886FD8 EIP = 0FF367F3 ESP = 0031EEB8 EBP = 00000000 EFL = 00210287 

0x9fb8b000 = 0000000000000000 


Memory:

0x9FB8AFD8  04 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0  ......................................ð
0x9FB8AFFF  bf ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??  ¿......................................
Attachment #8426294 - Flags: approval-mozilla-beta?
Attachment #8426294 - Flags: approval-mozilla-beta+
Attachment #8426294 - Flags: approval-mozilla-aurora?
Attachment #8426294 - Flags: approval-mozilla-aurora+
Flags: sec-bounty?
Flags: sec-bounty?
Sorry I accidentally deleted one flag set by Curtis, so I added it back.
Flags: sec-bounty? → sec-bounty+
Whiteboard: [fixed in 32 by bug 996078] → [fixed in 32 by bug 996078][adv-main30+]
Alias: CVE-2014-1543
Reproduced the original issue using the following builds:
- http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/2014/04/2014-04-26-mozilla-central-debug/
- http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/2014/04/2014-04-26-03-02-04-mozilla-central/

Reproduced the original issue using the following steps: (Used a Win 8.1 x64 fully updated VM)
- Installed the vJoy driver, used the information from comment # 14 and unchecked Y and Z under "Configure vJoy" (reproduced without unchecking those values also)
- Ran fx and opened the POC that was attached in comment #0
- Received in debug builds: Assertion failure: aAxis.Length(), at c:\builds\moz2_slave\m-cen-w32-d-000000000000000000\build\dom\gamepad\Gamepad.cpp:66
- The none debug m-c build simply crashed

Went through verification using the following builds:
- http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/2014-06-10-mozilla-central-debug/
- http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/2014-06-10-03-02-02-mozilla-central/
- http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/2014-06-10-mozilla-aurora-debug/
- http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/2014-06-10-00-40-02-mozilla-aurora/
- http://ftp.mozilla.org/pub/mozilla.org/firefox/tinderbox-builds/mozilla-beta-win32-debug/latest/
- http://ftp.mozilla.org/pub/mozilla.org/firefox/releases/latest-beta/win32/en-US/

- Opened POC using several tab(s) and ensured that the crash wasn't occurring
- Opened POC using several window(s) and ensured that the crash wasn't occurring
- Opened POC using several e10s (Nightly) and ensured that the crash wasn't occurring
- Opened POC using several Private Windows and ensured that the crash wasn't occurring
- Left POC opened for about 2-3 minutes and ensured that fx wasn't crashing
- Opened POC in a single tab, created a new about:newtab, closed the previous POC tab and than re-opened POC in the new about:newtab

Ted, is this sufficient enough using the crashes rather than looking for the buffer overflows in the stack trace?
That should be sufficient to verify, thanks!
Flags: needinfo?(ted)
Status: RESOLVED → VERIFIED
Group: core-security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: