Talos Vulnerability Report

TALOS-2018-0614

Apple IntelHD5000 Graphics Delete Resource Privilege Escalation Vulnerability

January 3, 2019
CVE Number

CVE-2018-4456, CVE-2018-4451

Summary

A memory corruption vulnerability exists in the IntelHD5000 kernel extension when dealing with graphics resources inside of OSX 10.13.4. A library inserted into the VLC media application can cause an out-of-bounds access inside of the KEXT leading to a use after free and invalid memory access in the context of the kernel. This can be used for privilege escalation.

Tested Versions

OS X 10.13.4 - MacBookPro11,4

Product URLs

https://www.apple.com/

CVSSv3 Score

8.8 - CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

CWE

CWE-416: Use After Free

Details

Apple supports multiple different GPU versions inside of OSX. With this functionality comes multiple different kernel extensions assigned to deal with the details of interaction between user space and the kernel to get the graphics buffers drawn effectively. On the retina Macbook Pro the provided GPU is the Apple Intel HD 5000 processor. Therefore this kernel extension is used in graphics rendering and processing throughout and is the subject to a use-after-free privilege escalation vulnerability. The vulnerability is also reachable from inside the Safari sandbox creating a larger potential attack surface.

A brief look at Apple kernel extensions shows that it uses a restricted subset language and a unique way of communication between user space and the kernel known as IOKit. Essentially an IOKit extension inherits from a UserClient class and registers its own methods to handle user interaction. There are also various types that can be passed in to connect to different UserClients stored under the same umbrella name. Upon connection, a port is returned and this port is forwarded through in all further communications. In the POC included, VLC is used to handle this basic connection and port setup.

The issue itself arises in the IntelAccelerator user client type 6, IGAccelSharedUserClient. The kernel extension is responsible for resource delegation in regards to graphics processing. The data stored and returned here gets passed through into the GPU for rendering and processing. There are multiple methods for allocating and deleting resources as well as creating shared memory with user space. The issue arises inside of the IOAccelSharedUserClient2::delete_resource(uint) function. A snippet from this function is shown below.

int IOAccelSharedUserClient2::delete_resource(IOAccelSharedUserClient2 *this, unsigned int index)
{
  IOGraphicsAccelerator2 *v2; // rbx
  void *resource; // [rsp+8h] [rbp-28h]

  
  IOGraphicsAccelerator2::lock_busy(v2);
  (*(*v2 + 2128LL))(v2, "", 0LL);
  if ( IOAccelNamespace::lookupId(*(*(this + 32) + 32LL), index, &resource) )  [0]
  {
    if ( *(resource + 20) != 10 )
      IOAccelResource2::sharedRelease(resource)      [1]
    
    IOGraphicsAccelerator2::unlock_busy(v3);
    IOLockUnlock(v3[17]);
  }

A user supplied index value is passed in from user space and then used as an argument to the lookupId function, [0]. By passing in a valid value but not the intended value an incorrect resource can be selected for release. This resource is then passed into the release function and it is subsequently removed. By selecting a specific resource to delete we can cause it to be reused although it has already been released. As stated above the resources used inside of the IGAccelSharedUserClient eventually get passed into the GPU for processing in the form of data buffers.

CVE-2018-4456 Delete Resource 5

  //  DELETE RESOURCE (IntelAccelerator(type 6: IGAccelSharedUserClient) 
  //  SELECTOR 1         IOAccelSharedUserClient2::delete_resource(uint)
  if(inputCnt > 0 && IGAccelSharedUserClient == connection && selector == 1){
    //change resource to delete from 1 - 5
    if(input[0] == 1) input[0] = 5;                    [4]
  }

The code above is injected into a VLC process and sits inside the IOConnectCallMethod used to interact between userspace and the kernel. As can be seen, [4], converting the passed in argument from the value 1 to the value 5 causes this vulnerability to trigger. The execute function handling the data buffers is below.

int IntelMTLComputeFunctions::execute(
{
  ...

  IGAccelResource::get_tex_data(object, v211, v193, 0);                 [2]
  v89 = *(_QWORD *)&object->resource_obj_1;
  if ( !v89 )                                                           [3]
    v89 = *(_QWORD *)&object->resource_obj_2;
  v90 = (*(__int64 (__fastcall **)(__int64, unsigned int *))(*(_QWORD *)v89 + 288LL))(v89, v211); [4]

The function above is the execution function for the Intel graphics processor. At location [2], a resource object is attained and accessed. Location [3] shows a check to verify the data is not null. Upon failure of this check the resource object is accessed again and a new value is returned. This returned value is then used directly without any further verification. This object is a reference to the object passed into delete above, [1], creating a use-after-free scenario. This can be leveraged by an attacker to execute arbitrary code in the context of the kernel. The attacker also has a large window of time to set up the attack as the execute function above is actually triggered from user space as well.

CVE-2018-4451 - Resource 7

  //  DELETE RESOURCE (IntelAccelerator(type 6: IGAccelSharedUserClient) 
  //  SELECTOR 1         IOAccelSharedUserClient2::delete_resource(uint)
  if(inputCnt > 0 && IGAccelSharedUserClient == connection && selector == 1){
    //change resource to delete from 1 - 7
    if(input[0] == 1) input[0] = 7;                    [4]
  }

The code above is injected into a VLC process and sits inside the IOConnectCallMethod used to interact between userspace and the kernel. As can be seen, [4], converting the passed in argument from the value 1 to the value 7 causes this vulnerability to trigger. The crashing function is below.

IOAccelMemoryMap * IOAccelResource2::prepareInTaskWithOption(IOAccelResource2IGAccelResource *this, IOAccelTask *a2, unsigned int a3)
{
  v3 = a3;
  while ( 1 )
  {
    v5 = *&this->resource_obj_1;                   [5]
    if ( !v5 )
      v5 = *&this->resource_obj_2;
    v6 = (*(*v5 + 312LL))(v5, a2, v3);             [6]

As above, the code accesses one resource object then verifies if it is null, [5]. If it is null then a second resource object is used without verification leading to a use after free, [6]. This can be used to gain arbitrary code execution and escalated privileges.

Crash Information

Delete Resource 7

*** Panic Report ***
panic(cpu 6 caller 0xffffff8011ed7bc6): Kernel trap at 0xffffff7f93014ff2, type 14=page fault, registers:
CR0: 0x0000000080010033, CR2: 0x0000000000000000, CR3: 0x000000039180f0e4, CR4: 0x00000000001627e0
RAX: 0x0000000000000001, RBX: 0xffffff8041d83000, RCX: 0xffffff80374bb000, RDX: 0x0000000000000003
RSP: 0xffffff9203fcb4f0, RBP: 0xffffff9203fcb520, RSI: 0xffffff8038669000, RDI: 0x0000000000000000
R8:  0x0000000042475241, R9:  0x00000000001b001b, R10: 0xffffff81dcbed000, R11: 0x0000000000000001
R12: 0xffffff8041d83000, R13: 0xffffff8042c16a00, R14: 0x0000000000000003, R15: 0xffffff8038669000
RFL: 0x0000000000010246, RIP: 0xffffff7f93014ff2, CS:  0x0000000000000008, SS:  0x0000000000000010
Fault CR2: 0x0000000000000000, Error code: 0x0000000000000000, Fault CPU: 0x6, PL: 0, VF: 0

Backtrace (CPU 6), Frame : Return Address
0xffffff9203fcafc0 : 0xffffff8011d7e1f6 mach_kernel : _handle_debugger_trap + 0x4e6
0xffffff9203fcb010 : 0xffffff8011ee6b74 mach_kernel : _kdp_i386_trap + 0x164
0xffffff9203fcb050 : 0xffffff8011ed79da mach_kernel : _kernel_trap + 0x51a
0xffffff9203fcb0c0 : 0xffffff8011d221f0 mach_kernel : trap_from_kernel + 0x26
0xffffff9203fcb0e0 : 0xffffff8011d7d8ea mach_kernel : _panic_trap_to_debugger + 0x20a
0xffffff9203fcb210 : 0xffffff8011d7d6bc mach_kernel : _panic + 0x5c
0xffffff9203fcb270 : 0xffffff8011ed7bc6 mach_kernel : _kernel_trap + 0x706
0xffffff9203fcb3e0 : 0xffffff8011d221f0 mach_kernel : trap_from_kernel + 0x26
0xffffff9203fcb400 : 0xffffff7f93014ff2 com.apple.iokit.IOAcceleratorFamily2 : __ZN16IOAccelResource223prepareInTaskWithOptionEP11IOAccelTaskj + 0x2c
0xffffff9203fcb520 : 0xffffff7f9436feac com.apple.driver.AppleIntelHD5000Graphics : __ZN15IGAccelResource20prepareKernelMappingEv + 0x92
0xffffff9203fcb540 : 0xffffff7f94343b47 com.apple.driver.AppleIntelHD5000Graphics : __ZN24IntelMTLComputeFunctions7executeEN15IntelMTLCompute7eTokensER19IGAccelCommandQueueR26IGAccelSegmentResourceListRK20IOAccelKernelCommandR24IGAccelCommandDescriptorR22IOGraphicsAccelerator2R17IGHardwareContextR12IOAccelEvent + 0xdb
0xffffff9203fcb640 : 0xffffff7f94347847 com.apple.driver.AppleIntelHD5000Graphics : __ZN19IGAccelCommandQueue27processSegmentKernelCommandEP26IOAccelSegmentResourceListPK20IOAccelKernelCommandS4_ + 0xc9
0xffffff9203fcb680 : 0xffffff7f9302fdf1 com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue28processSegmentKernelCommandsEP26IOAccelSegmentResourceListPK20IOAccelKernelCommandS4_ + 0x5f
0xffffff9203fcb6b0 : 0xffffff7f943476db com.apple.driver.AppleIntelHD5000Graphics : __ZN19IGAccelCommandQueue28processSegmentKernelCommandsEP26IOAccelSegmentResourceListPK20IOAccelKernelCommandS4_ + 0x67
0xffffff9203fcb6f0 : 0xffffff7f9302ff81 com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue33processAndSubmitCoalescedSegmentsEP26IOAccelCommandQueueSegmentPj + 0x55
0xffffff9203fcb730 : 0xffffff7f930306bc com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue20processCommandBufferEjj + 0x5ee
0xffffff9203fcb9e0 : 0xffffff7f94347d6f com.apple.driver.AppleIntelHD5000Graphics : __ZN19IGAccelCommandQueue20processCommandBufferEjj + 0x49
0xffffff9203fcba10 : 0xffffff7f9302f6ac com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue19submitCommandBufferEjjyy + 0xf0
0xffffff9203fcba60 : 0xffffff7f9302f4b7 com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue22submit_command_buffersEPK29IOAccelCommandQueueSubmitArgs + 0x235
0xffffff9203fcbab0 : 0xffffff7f9302e6aa com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue24s_submit_command_buffersEPS_PvP25IOExternalMethodArguments + 0x108
0xffffff9203fcbaf0 : 0xffffff8012465ff8 mach_kernel : __ZN12IOUserClient14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv + 0x1d8
0xffffff9203fcbb40 : 0xffffff7f94347b60 com.apple.driver.AppleIntelHD5000Graphics : __ZN19IGAccelCommandQueue14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv + 0x1c
0xffffff9203fcbb70 : 0xffffff801246ed67 mach_kernel : _is_io_connect_method + 0x217
0xffffff9203fcbcb0 : 0xffffff8011e8c124 mach_kernel : __Xio_connect_method + 0x174
0xffffff9203fcbdc0 : 0xffffff8011d83ca7 mach_kernel : _ipc_kobject_server + 0x127
0xffffff9203fcbe10 : 0xffffff8011d56cad mach_kernel : _ipc_kmsg_send + 0x10d
0xffffff9203fcbe60 : 0xffffff8011d71a9b mach_kernel : _mach_msg_overwrite_trap + 0x37b
0xffffff9203fcbef0 : 0xffffff8011ebff8a mach_kernel : _mach_call_munger64 + 0x23a
0xffffff9203fcbfa0 : 0xffffff8011d229f6 mach_kernel : _hndl_mach_scall64 + 0x16
      Kernel Extensions in backtrace:
         com.apple.iokit.IOAcceleratorFamily2(378.18.1)[BAA0383C-9650-3934-B04A-69008F757A2C]@0xffffff7f92ffb000->0xffffff7f93091fff
            dependency: com.apple.driver.AppleMobileFileIntegrity(1.0.5)[54CD88E5-9FD7-30FC-89A0-E4B2D0CE6F85]@0xffffff7f92f74000
            dependency: com.apple.iokit.IOSurface(211.12)[E998B85B-3174-3C25-B82B-C0D8BD9720E5]@0xffffff7f92f89000
            dependency: com.apple.iokit.IOPCIFamily(2.9)[1850E7DA-E707-3027-A3AA-637C80B57219]@0xffffff7f92694000
            dependency: com.apple.iokit.IOGraphicsFamily(519.15)[D5F2A20D-CAB0-33B2-91B9-E8755DFC34CB]@0xffffff7f92fa5000
         com.apple.driver.AppleIntelHD5000Graphics(10.3.2)[18CF1D18-BC94-3F6A-8711-8921CE16E38B]@0xffffff7f9433c000->0xffffff7f943d9fff
            dependency: com.apple.iokit.IOSurface(211.12)[E998B85B-3174-3C25-B82B-C0D8BD9720E5]@0xffffff7f92f89000
            dependency: com.apple.iokit.IOPCIFamily(2.9)[1850E7DA-E707-3027-A3AA-637C80B57219]@0xffffff7f92694000
            dependency: com.apple.iokit.IOGraphicsFamily(519.15)[D5F2A20D-CAB0-33B2-91B9-E8755DFC34CB]@0xffffff7f92fa5000
            dependency: com.apple.iokit.IOAcceleratorFamily2(378.18.1)[BAA0383C-9650-3934-B04A-69008F757A2C]@0xffffff7f92ffb000

BSD process name corresponding to current thread: VLC
Boot args: debug=0x146 kdp_match_name=en6 kext-dev-mode=1 pmuflags=1 -v keepsyms=1 

Mac OS version:
17E199

Kernel version:
Darwin Kernel Version 17.5.0: Fri Apr 13 19:32:32 PDT 2018; root:xnu-4570.51.2~1/DEVELOPMENT_X86_64
Kernel UUID: 8202BF9D-0810-353F-9453-77740F1F2D33
Kernel slide:     0x0000000011a00000
Kernel text base: 0xffffff8011c00000
__HIB  text base: 0xffffff8011b00000
System model name: MacBookPro11,4 (Mac-06F11FD93F0323C5)


Delete Resource 5

*** Panic Report ***
panic(cpu 2 caller 0xffffff801f4d7bc6): Kernel trap at 0xffffff7fa19440f4, type 14=page fault, registers:
CR0: 0x0000000080010033, CR2: 0x0000000000000000, CR3: 0x000000034c966142, CR4: 0x00000000001627e0
RAX: 0x0000000000000080, RBX: 0xffffff81ecb2601c, RCX: 0x0000000000000000, RDX: 0xffffff805ade09f0
RSP: 0xffffff92115d3550, RBP: 0xffffff92115d3640, RSI: 0x0000000000000000, RDI: 0x0000000000000000
R8:  0xffffff805166e680, R9:  0x00000000001b001b, R10: 0xffffff81ecb2601c, R11: 0x0000000000000001
R12: 0xffffff92115d3560, R13: 0xffffff805166e680, R14: 0xffffff805e475800, R15: 0xffffff8050659000
RFL: 0x0000000000010246, RIP: 0xffffff7fa19440f4, CS:  0x0000000000000008, SS:  0x0000000000000010
Fault CR2: 0x0000000000000000, Error code: 0x0000000000000000, Fault CPU: 0x2, PL: 0, VF: 0

Backtrace (CPU 2), Frame : Return Address
0xffffff92115d3020 : 0xffffff801f37e1f6 mach_kernel : _handle_debugger_trap + 0x4e6
0xffffff92115d3070 : 0xffffff801f4e6b74 mach_kernel : _kdp_i386_trap + 0x164
0xffffff92115d30b0 : 0xffffff801f4d79da mach_kernel : _kernel_trap + 0x51a
0xffffff92115d3120 : 0xffffff801f3221f0 mach_kernel : trap_from_kernel + 0x26
0xffffff92115d3140 : 0xffffff801f37d8ea mach_kernel : _panic_trap_to_debugger + 0x20a
0xffffff92115d3270 : 0xffffff801f37d6bc mach_kernel : _panic + 0x5c
0xffffff92115d32d0 : 0xffffff801f4d7bc6 mach_kernel : _kernel_trap + 0x706
0xffffff92115d3440 : 0xffffff801f3221f0 mach_kernel : trap_from_kernel + 0x26
0xffffff92115d3460 : 0xffffff7fa19440f4 com.apple.driver.AppleIntelHD5000Graphics : __ZN24IntelMTLComputeFunctions7executeEN15IntelMTLCompute7eTokensER19IGAccelCommandQueueR26IGAccelSegmentResourceListRK20IOAccelKernelCommandR24IGAccelCommandDescriptorR22IOGraphicsAccelerator2R17IGHardwareContextR12IOAccelEvent + 0x688
0xffffff92115d3640 : 0xffffff7fa1947847 com.apple.driver.AppleIntelHD5000Graphics : __ZN19IGAccelCommandQueue27processSegmentKernelCommandEP26IOAccelSegmentResourceListPK20IOAccelKernelCommandS4_ + 0xc9
0xffffff92115d3680 : 0xffffff7fa062fdf1 com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue28processSegmentKernelCommandsEP26IOAccelSegmentResourceListPK20IOAccelKernelCommandS4_ + 0x5f
0xffffff92115d36b0 : 0xffffff7fa19476db com.apple.driver.AppleIntelHD5000Graphics : __ZN19IGAccelCommandQueue28processSegmentKernelCommandsEP26IOAccelSegmentResourceListPK20IOAccelKernelCommandS4_ + 0x67
0xffffff92115d36f0 : 0xffffff7fa062ff81 com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue33processAndSubmitCoalescedSegmentsEP26IOAccelCommandQueueSegmentPj + 0x55
0xffffff92115d3730 : 0xffffff7fa06306bc com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue20processCommandBufferEjj + 0x5ee
0xffffff92115d39e0 : 0xffffff7fa1947d6f com.apple.driver.AppleIntelHD5000Graphics : __ZN19IGAccelCommandQueue20processCommandBufferEjj + 0x49
0xffffff92115d3a10 : 0xffffff7fa062f6ac com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue19submitCommandBufferEjjyy + 0xf0
0xffffff92115d3a60 : 0xffffff7fa062f4b7 com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue22submit_command_buffersEPK29IOAccelCommandQueueSubmitArgs + 0x235
0xffffff92115d3ab0 : 0xffffff7fa062e6aa com.apple.iokit.IOAcceleratorFamily2 : __ZN19IOAccelCommandQueue24s_submit_command_buffersEPS_PvP25IOExternalMethodArguments + 0x108
0xffffff92115d3af0 : 0xffffff801fa65ff8 mach_kernel : __ZN12IOUserClient14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv + 0x1d8
0xffffff92115d3b40 : 0xffffff7fa1947b60 com.apple.driver.AppleIntelHD5000Graphics : __ZN19IGAccelCommandQueue14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv + 0x1c
0xffffff92115d3b70 : 0xffffff801fa6ed67 mach_kernel : _is_io_connect_method + 0x217
0xffffff92115d3cb0 : 0xffffff801f48c124 mach_kernel : __Xio_connect_method + 0x174
0xffffff92115d3dc0 : 0xffffff801f383ca7 mach_kernel : _ipc_kobject_server + 0x127
0xffffff92115d3e10 : 0xffffff801f356cad mach_kernel : _ipc_kmsg_send + 0x10d
0xffffff92115d3e60 : 0xffffff801f371a9b mach_kernel : _mach_msg_overwrite_trap + 0x37b
0xffffff92115d3ef0 : 0xffffff801f4bff8a mach_kernel : _mach_call_munger64 + 0x23a
0xffffff92115d3fa0 : 0xffffff801f3229f6 mach_kernel : _hndl_mach_scall64 + 0x16
      Kernel Extensions in backtrace:
         com.apple.iokit.IOAcceleratorFamily2(378.18.1)[BAA0383C-9650-3934-B04A-69008F757A2C]@0xffffff7fa05fb000->0xffffff7fa0691fff
            dependency: com.apple.driver.AppleMobileFileIntegrity(1.0.5)[54CD88E5-9FD7-30FC-89A0-E4B2D0CE6F85]@0xffffff7fa0574000
            dependency: com.apple.iokit.IOSurface(211.12)[E998B85B-3174-3C25-B82B-C0D8BD9720E5]@0xffffff7fa0589000
            dependency: com.apple.iokit.IOPCIFamily(2.9)[1850E7DA-E707-3027-A3AA-637C80B57219]@0xffffff7f9fc94000
            dependency: com.apple.iokit.IOGraphicsFamily(519.15)[D5F2A20D-CAB0-33B2-91B9-E8755DFC34CB]@0xffffff7fa05a5000
         com.apple.driver.AppleIntelHD5000Graphics(10.3.2)[18CF1D18-BC94-3F6A-8711-8921CE16E38B]@0xffffff7fa193c000->0xffffff7fa19d9fff
            dependency: com.apple.iokit.IOSurface(211.12)[E998B85B-3174-3C25-B82B-C0D8BD9720E5]@0xffffff7fa0589000
            dependency: com.apple.iokit.IOPCIFamily(2.9)[1850E7DA-E707-3027-A3AA-637C80B57219]@0xffffff7f9fc94000
            dependency: com.apple.iokit.IOGraphicsFamily(519.15)[D5F2A20D-CAB0-33B2-91B9-E8755DFC34CB]@0xffffff7fa05a5000
            dependency: com.apple.iokit.IOAcceleratorFamily2(378.18.1)[BAA0383C-9650-3934-B04A-69008F757A2C]@0xffffff7fa05fb000

BSD process name corresponding to current thread: VLC
Boot args: debug=0x146 kdp_match_name=en6 kext-dev-mode=1 pmuflags=1 -v keepsyms=1 

Mac OS version:
17E199

Kernel version:
Darwin Kernel Version 17.5.0: Fri Apr 13 19:32:32 PDT 2018; root:xnu-4570.51.2~1/DEVELOPMENT_X86_64
Kernel UUID: 8202BF9D-0810-353F-9453-77740F1F2D33
Kernel slide:     0x000000001f000000
Kernel text base: 0xffffff801f200000
__HIB  text base: 0xffffff801f100000
System model name: MacBookPro11,4 (Mac-06F11FD93F0323C5)

Exploit Proof of Concept

Attached are two proof of concepts. These need to be built as shared libraries using the command in the comments at the head of the file. These libraries are then injected into VLC with the provided movie as an argument. These instructions are also included at the head of each of the files. I have tested with VLC versions 3.0.2 and 2.2.4 with successful results. Other builds may differ.

Timeline

2018-05-29 - Vendor disclosure
2018-12-24 - Vendor patched and released update
2019-01-08 - Public release

Credit

Discovered by Tyler Bohan of Cisco Talos.