|
|
OS X IOKit kernel multiple exploitable memory safety issues in token parsing in IGAccelVideoContextMedia (x5) | ||||||
| Project Member Reported by ianbeer@google.com, Jun 12 2014 | Back to list | ||||||
IGAccelVideoContextMedia is the userclient responsible for gpu accelerated video decoding - it's userclient type 0x101 of the IntelAccelerator IOService. Clients of IGAccelVideoContextMedia call IOConnectMapMemory with type=0 to map a shared buffer which is used to pass tokens to the kernel. The IGAccelVideoContextMedia::process_token_* methods parse these tokens (offset +0x10 of the IOAccelCommandStreamInfo& which is passed to the process_token_* methods is a pointer into the shared buffer.) There are multiple cases of insufficient bounds checking allowing an attacker to get controlled writes to kernel memory - please see each of the attached PoCs for more details of each bug. This userclient can be reached from the chrome GPU process sandbox and the safari renderer sandbox. These PoCs are interpose libraries which have been tested by loading them into Quicktime, the bugs are still reachable from chrome and safari, but Quicktime hits more of the kernel video code (so required less effort to write the PoCs for.) The attached Makefile will build all the libraries, load them like this: DYLD_INSERT_LIBRARIES=<path/to/this/lib.dylib> /Applications/QuickTime\ Player.app/Contents/MacOS/QuickTime\ Player and open an mp4 file
Project Member
Comment 1
by
ianbeer@google.com,
Jun 12 2014
,
Jun 12 2014
,
Jun 21 2014
,
Jun 25 2014
Apple asked for more details so here's a more detailed explanation of the bugs and more PoCs - I also sent apple panic logs, kernel debugger logs and system profiler information for my test system but I won't upload those here.
,
Jun 25 2014
(the bugtracker might mess up the formatting of this - it's attached as more_detailed_writeup to the previous comment) These token bugs were all found via manually reversing the driver so I'll try to explain them in more detail: *** ig_video_media_avc_decode_oob_write.c *** This bug is in the function IGAccelVideoContextMedia::process_token_AVCDecode(IOAccelCommandStreamInfo &) in AppleIntelHD4000Graphics (function is at offset +0x1FB3A in the kext) Presumably this function has something to do with decoding this: https://en.wikipedia.org/wiki/H.264/MPEG-4_AVC This code it hit when playing an h.264/AVC file, for example this apple movie trailer should work: http://movietrailers.apple.com/movies/independent/abronytale/abronytale-tlr1_480p.mov (this url is actually fine for all these PoCs - load the respective interpose library into quicktime with DYLD_INSERT_LIBRARIES then select "Open Location" from the "File" menu and paste that url.) The pointer at offset 0x10 of the IOAccelCommandStreamInfo which is passed by reference as the argument to this function points into shared memory. It's the token buffer which a userclient maps using memoryType==0 of IOConnectMapMemory on the IGAccelVideoContextMedia userclient. This token decode function will be called for a token with the token id field == 0x8c00 __text:000000000001FB3A ; IGAccelVideoContextMedia::process_token_AVCDecode(IOAccelCommandStreamInfo &) __text:000000000001FB3A __text:000000000001FB3A push rbp __text:000000000001FB3B mov rbp, rsp __text:000000000001FB3E push r15 __text:000000000001FB40 push r14 __text:000000000001FB42 push r13 __text:000000000001FB44 push r12 __text:000000000001FB46 push rbx __text:000000000001FB47 sub rsp, 28h __text:000000000001FB4B mov [rbp+var_40], rsi ; rsi is the pointer to the IOAccelCommandStreamInfo structure __text:000000000001FB4F mov r15, rdi __text:000000000001FB52 mov rax, [rsi] __text:000000000001FB55 mov [rbp+var_48], rax __text:000000000001FB59 mov r14, [rsi+10h] ; offset 0x10 is the pointer to the token buffer ; r14 points to user-controlled data ... further down this function there's this double-nested loop: (r14 hasn't changed - it still points into the token buffer) __text:000000000001FD4F xor r9d, r9d __text:000000000001FD52 mov rbx, r9 ; initialize loop counter to zero __text:000000000001FD55 __text:000000000001FD55 loc_1FD55: __text:000000000001FD55 mov eax, [r14+rbx*4+900h] ; read a dword from r14 + loop_iteration*4 + 0x900 into eax __text:000000000001FD5D lea rdi, [r10+rax*4] ; use that dword to compute a pointer into the buffer pointed to by r10, without ; checking if it's outside the bounds (no write yet though) __text:000000000001FD61 mov rax, r12 __text:000000000001FD64 mov rsi, r9 __text:000000000001FD67 __text:000000000001FD67 loc_1FD67: ; inner loop __text:000000000001FD67 mov edx, [rax] __text:000000000001FD69 shr edx, 6 __text:000000000001FD6C shl rdx, 4 __text:000000000001FD70 mov edx, [r11+rdx+4] __text:000000000001FD75 or edx, 2 __text:000000000001FD78 mov [rdi+rsi*4], edx ; write a value using rdi as the base pointer (which was computed by the lea above ; at 0x1fd5d.) This is the OOB write. The value read from the token buffer at 0x1fd55 ; was never checked to fall within the bounds of the buffer pointed to by r10 __text:000000000001FD7B add rax, 4 __text:000000000001FD7F inc rsi __text:000000000001FD82 cmp esi, 22h ; '"' __text:000000000001FD85 jnz short loc_1FD67 __text:000000000001FD87 add r12, 114h __text:000000000001FD8E inc rbx __text:000000000001FD91 cmp ebx, r8d __text:000000000001FD94 jnz short loc_1FD55 *** ig_video_media_avcpak_oob_write.c *** AVCPAK is another token type (token id == 0x8c00) __text:000000000001F726 ; IGAccelVideoContextMedia::process_token_AVCPAK(IOAccelCommandStreamInfo &) __text:000000000001F726 __text:000000000001F726 push rbp __text:000000000001F727 mov rbp, rsp __text:000000000001F72A push r15 __text:000000000001F72C push r14 __text:000000000001F72E push r13 __text:000000000001F730 push r12 __text:000000000001F732 push rbx __text:000000000001F733 sub rsp, 38h __text:000000000001F737 mov r14, rsi ; pointer to IOAccelCommandStreamInfo __text:000000000001F73A mov r12, rdi __text:000000000001F73D mov rax, [r14] __text:000000000001F740 mov [rbp+var_40], rax __text:000000000001F744 mov rbx, [r14+10h] ; pointer to token buffer saved in rbx __text:000000000001F748 mov eax, [rbx+8] ; setting this dword to zero skips the call to bind_resource and jumps closer to the bug __text:000000000001F74B mov [rbp+var_44], eax __text:000000000001F74E test eax, eax __text:000000000001F750 jz short loc_1F7C0 ... further down: __text:000000000001F7D4 mov r9d, [rbx+81Ch] ; read dword from token buffer at offset 0x81c into r9d (r9d now attacked controlled) __text:000000000001F7DB mov r10, [rbp+var_40] __text:000000000001F7DF lea rsi, [r10+r9*4+34h] __text:000000000001F7E4 shl rax, 4 __text:000000000001F7E8 mov eax, [rcx+rax+4] __text:000000000001F7EC and eax, 0FFFFFFC0h __text:000000000001F7EF xor edi, edi __text:000000000001F7F1 or eax, 2 __text:000000000001F7F4 mov [r10+r9*4+1Ch], eax ; r9 used as the offset for a memory write here without checking that it falls within ; the bounds of the buffer pointed to by r10 *** ig_video_media_avcpak_oob_write_2.c *** __text:000000000001F726 ; IGAccelVideoContextMedia::process_token_AVCPAK(IOAccelCommandStreamInfo &) __text:000000000001F726 __text:000000000001F726 push rbp __text:000000000001F727 mov rbp, rsp __text:000000000001F72A push r15 __text:000000000001F72C push r14 __text:000000000001F72E push r13 __text:000000000001F730 push r12 __text:000000000001F732 push rbx __text:000000000001F733 sub rsp, 38h __text:000000000001F737 mov r14, rsi ; pointer to IOAccelCommandStreamInfo __text:000000000001F73A mov r12, rdi __text:000000000001F73D mov rax, [r14] __text:000000000001F740 mov [rbp+var_40], rax __text:000000000001F744 mov rbx, [r14+10h] ; save pointer to token buffer in rbx ... __text:000000000001F91D mov r8, rbx ; after this point - until the next call - r8 points to the token buffer ... __text:000000000001F9CD mov eax, [r8+820h] ; read the dword at offset 0x820 into eax __text:000000000001F9D4 mov rdx, [rbp+var_40] __text:000000000001F9D8 lea rsi, [rdx+rax*4+84h] __text:000000000001F9E0 mov [rbp+var_50], rsi __text:000000000001F9E4 lea rdx, [rdx+rax*4+4] __text:000000000001F9E9 mov [rbp+var_58], rdx __text:000000000001F9ED lea r13, [r8+239Ch] __text:000000000001F9F4 lea rbx, [r8+231Ch] __text:000000000001F9FB xor r9d, r9d __text:000000000001F9FE lea r11, [rax+1] ; move that dword + 1 into r11 ... __text:000000000001FA84 add r15, r11 ; add the controlled dword r11 to r15 __text:000000000001FA87 mov eax, [r14+114h] __text:000000000001FA8E add eax, [rbp+var_44] __text:000000000001FA91 and eax, 0FFFFFFFCh __text:000000000001FA94 mov rdx, [rbp+var_40] __text:000000000001FA98 mov [rdx+r15*4], eax ; use r15 as an offset into the buffer pointed to by rdx *** ig_video_media_patch_avc_wa_oob_write.c *** __text:000000000001FB3A ; IGAccelVideoContextMedia::process_token_AVCDecode(IOAccelCommandStreamInfo &) __text:000000000001FB3A __text:000000000001FB3A push rbp __text:000000000001FB3B mov rbp, rsp __text:000000000001FB3E push r15 __text:000000000001FB40 push r14 __text:000000000001FB42 push r13 __text:000000000001FB44 push r12 __text:000000000001FB46 push rbx __text:000000000001FB47 sub rsp, 28h __text:000000000001FB4B mov [rbp+var_40], rsi ; rsi points to IOAccelCommandStreamInfo __text:000000000001FB4F mov r15, rdi __text:000000000001FB52 mov rax, [rsi] __text:000000000001FB55 mov [rbp+var_48], rax __text:000000000001FB59 mov r14, [rsi+10h] ; save pointer to token buffer in r14 ... __text:000000000001FD96 mov eax, [r14+814h] ; read dword at offset 0x814 in token buffer __text:000000000001FD9D lea rdx, [r13+rax*4+0] ; use that as an offset to compute a pointer into the buffer pointer to by r13 ; without checking any bounds ; this pointer is passed as the uint* argument to the call to ; IGAccelVideoContextMedia::patch_AVC_WA below __text:000000000001FDA2 mov rbx, r15 __text:000000000001FDA5 mov rdi, rbx __text:000000000001FDA8 mov rsi, [rbp+var_40] __text:000000000001FDAC call IGAccelVideoContextMedia::patch_AVC_WA(IOAccelCommandStreamInfo &,uint *,sIntelVideoTokenArgsWADummyJPEG *) ... __text:00000000000205CE ; IGAccelVideoContextMedia::patch_AVC_WA(IOAccelCommandStreamInfo &, unsigned int *, sIntelVideoTokenArgsWADummyJPEG *) __text:00000000000205CE __text:00000000000205CE push rbp __text:00000000000205CF mov rbp, rsp __text:00000000000205D2 push r15 __text:00000000000205D4 push r14 __text:00000000000205D6 push r13 __text:00000000000205D8 push r12 __text:00000000000205DA push rbx __text:00000000000205DB sub rsp, 28h __text:00000000000205DF mov r12, rcx __text:00000000000205E2 mov rbx, rdx ; save rdx (controlled out-of-bounds pointer) to rbx __text:00000000000205E5 mov r14, rsi __text:00000000000205E8 mov r15, rdi __text:00000000000205EB mov rax, [r15] __text:00000000000205EE mov edx, [r12] __text:00000000000205F2 mov [rsp+50h+var_50], 1 __text:00000000000205F9 lea rcx, [rbp+var_30] __text:00000000000205FD lea r8, [rbp+var_34] __text:0000000000020601 lea r9, [rbp+var_38] __text:0000000000020605 call qword ptr [rax+0A98h] __text:000000000002060B test al, al __text:000000000002060D jz loc_207B6 __text:0000000000020613 mov eax, [rbp+var_34] __text:0000000000020616 mov [rbx+40h], eax ; use rbx as the base register for a memory write
,
Aug 22 2014
,
Sep 10 2014
Deadline exceeded -- automatically derestricting
,
Sep 23 2014
http://support.apple.com/kb/HT6443 CVE-2014-4401 (ig_video_media_avc_decode_oob_read) CVE-2014-4396 (ig_video_media_avc_decode_oob_write) CVE-2014-4397 (ig_video_media_avcpak_oob_write_2) CVE-2014-4400 (ig_video_media_avcpak_oob_write) CVE-2014-4399 (ig_video_media_patch_avc_wa_oob_write) |
|||||||
| ► Sign in to add a comment | |||||||