New issue
Advanced search Search tips
Starred by 1 user
Status: Fixed
Owner:
Closed: Dec 2015
Cc:



Sign in to add a comment
Lack of bounds checking in gst_configure leads to kernel buffer overflow due to toctou (plus kernel memory disclosure)
Project Member Reported by ianbeer@google.com, Oct 26 2015 Back to list
The external method 0x206 of IGAccelGLContext is gst_configure. This method takes an arbitrary sized input structure
(passed in rsi) but doesn't check the size of that structure (passed in rcx.)

__text:000000000002A366 __ZN16IGAccelGLContext13gst_configureEP19GstConfigurationRecS1_jPj proc near
__text:000000000002A366                                         ; DATA XREF: __const:000000000005BF88o
__text:000000000002A366                 push    rbp
__text:000000000002A367                 mov     rbp, rsp
__text:000000000002A36A                 push    r15
__text:000000000002A36C                 push    r14
__text:000000000002A36E                 push    r12
__text:000000000002A370                 push    rbx
__text:000000000002A371                 mov     rax, rdx
__text:000000000002A374                 mov     r15, rsi         ; <-- r15 points to controlled mach message data
__text:000000000002A377                 mov     r14, rdi
__text:000000000002A37A                 mov     edx, [r15+800h]  ; <-- size never checked -> oob read
__text:000000000002A381                 cmp     edx, 200h
__text:000000000002A387                 jbe     short loc_2A3AD
__text:000000000002A389                 lea     rdi, aIgaccelglcon_0 ; "IGAccelGLContext::%s Error: Number of e"...
__text:000000000002A390                 lea     rsi, aGst_configure ; "gst_configure"
__text:000000000002A397                 mov     ecx, 200h
__text:000000000002A39C                 xor     eax, eax
__text:000000000002A39E                 call    _IOLog


here we can see that the method is reading a dword at offset 0x800 of the input struct and comparing that value to 0x200.
This method is reached via MIG and if we call userspace IOConnectCallMethod with a small input struct then the mach
message is actually packed such that only the input struct size we send actually gets sent; therefore this is an OOB read.

The first interesting conseqeuence of this is that if the value read is > 0x200 then it gets logged to /var/log/system.log
which we can read from userspace allowing us to disclose some kernel memory.

However, we can do more:

r15 is passed to IntelAccelerator::gstqConfigure:

mov     rsi, r15
call    __ZN16IntelAccelerator13gstqConfigureEP19GstConfigurationRec

where we reach the following code:

__text:000000000001DC29                 mov     edx, [rsi+800h]
__text:000000000001DC2F                 shl     rdx, 2          ; size_t
__text:000000000001DC33                 lea     rdi, _gstCustomCounterConfigPair ; void *
__text:000000000001DC3A                 call    _memcpy

here the value at +0x800 is read again and used as the size for a memcpy assuming that it has already been verified, but
since it's outside the bounds of the allocation this is actually a toctou bug since with some heap manipulation we can
change that value to be > 0x200 allowing us to overflow the _gstCustomCounterConfigPair buffer.

Since the struct input comes from a mach message this heap grooming shouldn't be that difficult.

clang -o ig_gl_gst_oob_read ig_gl_gst_oob_read.c -framework IOKit

repro: while true; ./ig_gl_gst_oob_read; done

Tested on OS X ElCapitan 10.11.1 (15b42) on MacBookAir5,2
 
ig_gl_gst_oob_read.c
5.3 KB Download
Project Member Comment 1 by ianbeer@google.com, Oct 26 2015
Labels: Reported-2015-Oct-26 Id-630664448
Project Member Comment 2 by ianbeer@google.com, Dec 20 2015
Labels: CVE-2015-7077 Fixed-2015-Dec-08
Status: Fixed
Apple advisory: https://support.apple.com/en-gb/HT205637
Project Member Comment 3 by ianbeer@google.com, Jan 27 2016
Labels: -Restrict-View-Commit
Sign in to add a comment