Lucene search
K

Apple OS X/iOS - 'mach_ports_register' Multiple Memory Safety s

🗓️ 31 Oct 2016 00:00:00Reported by Google Security ResearchType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 79 Views

Multiple memory safety vulnerabilities in mach_ports_register function in Apple OS X/iOS kernel.

Code
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=882

mach_ports_register is a kernel task port MIG method.

It's defined in MIG like this:

  routine mach_ports_register(
      target_task : task_t;
      init_port_set : mach_port_array_t =
            ^array[] of mach_port_t);

Looking at the generated code for this we notice something kinda weird; here's the mach message structure
which actually gets sent:

  typedef struct {
    mach_msg_header_t Head;
    // start of the kernel processed data
    mach_msg_body_t msgh_body;
    mach_msg_ool_ports_descriptor_t init_port_set;
    // end of the kernel processed data
    NDR_record_t NDR;
    mach_msg_type_number_t init_port_setCnt;
  } Request __attribute__((unused));

The message contains an OOL ports descriptor, which is expected, but also contains a separate init_port_setCnt value
even though the ool_ports_descriptor_t already has the correct length of the descriptor.

When the kernel process this ool ports descriptor in ipc_kmsg_copyin_ool_ports_descriptor it will kalloc a buffer large enough
for all the ports and then copyin and convert them all. It does this using the init_port_set.count value, not init_port_setCnt.

The generated MIG code however calls mach_ports_register like this:

  OutP->RetCode = mach_ports_register(target_task, (mach_port_array_t)(In0P->init_port_set.address), In0P->init_port_setCnt);

without verifying that In0P->init_port_setCnt is equal to init_port_set.count.

This means that when we reach mach_ports_register lots of stuff goes wrong:

  kern_return_t
  mach_ports_register(
    task_t      task,
    mach_port_array_t memory,                       <-- points to kalloc'ed buffer
    mach_msg_type_number_t  portsCnt)               <-- completely controlled, not related to size of kalloc'ed buffer
  {
    ipc_port_t ports[TASK_PORT_REGISTER_MAX];
    unsigned int i;

    if ((task == TASK_NULL) ||
        (portsCnt > TASK_PORT_REGISTER_MAX) ||
        (portsCnt && memory == NULL))
      return KERN_INVALID_ARGUMENT;                 <-- portsCnt must be >=1 && <= 3

    for (i = 0; i < portsCnt; i++)
      ports[i] = memory[i];                         <-- if we only sent one OOL port but set portsCnt >1 this will read a mach_port_t (a pointer) out of bounds
    for (; i < TASK_PORT_REGISTER_MAX; i++)
      ports[i] = IP_NULL;

    itk_lock(task);
    if (task->itk_self == IP_NULL) {
      itk_unlock(task);
      return KERN_INVALID_ARGUMENT;
    }

    for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
      ipc_port_t old;

      old = task->itk_registered[i];
      task->itk_registered[i] = ports[i];
      ports[i] = old;
    }

    itk_unlock(task);

    for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
      if (IP_VALID(ports[i]))
        ipc_port_release_send(ports[i]);           <-- this can decrement the ref on a pointer which was read out of bounds if we call this function multiple times

    if (portsCnt != 0)
      kfree(memory,
            (vm_size_t) (portsCnt * sizeof(mach_port_t)));   <-- this can call kfree with the wrong size

    return KERN_SUCCESS;
  }

For this PoC I've patched the MIG generated code to always only send one OOL mach port but still set init_port_setCnt to a controlled value - you should see a kernel
panic decrementing an invalid reference or something like that.

This bug however could be exploited quite nicely to cause a mach_port_t UaF which could have all kinds of fun consequences (getting another task's task port for example!)

tested on OS X 10.11.6 (15G31) on MacBookPro10,1


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40654.zip

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation