Skip to content

Instantly share code, notes, and snippets.

@b1n4r1b01
Last active May 27, 2024 06:40
Show Gist options
  • Save b1n4r1b01/8a79465e89de8a70a3cb12680a304b17 to your computer and use it in GitHub Desktop.
Save b1n4r1b01/8a79465e89de8a70a3cb12680a304b17 to your computer and use it in GitHub Desktop.
Some dumb bugs in AppleH10CamInUserClient

NULL Deref

AppleH10CamIn::ISP_RegisterFirmwareWorkProcessor_gated(AppleH10CamIn *this, uint64_t *inStr, io_user_reference_t *asyncRef, uint64_t this2){
	...
		if ( some_os_array->getCount() ){
			while ( true ){
				unk_object = *(uint64_t*)(some_os_array->getObject());
				idk = unk_object->unk_0xD8();
				old_port = *(uint64_t*)(idk + 0x48);
				port = *(uint64_t*)asyncRef;  <----(a)
				...
			}
			...
		}
	...
}

(a) By simply calling this externalMethod syncronously, asyncRef remains NULL thus NULL deref happens

This can be seen accross selector 43, 44, 45, 46. Selector 45 requires the camera to be turned on so you can run this PoC while taking a selfie.

if ( !*(&this->unk + 3) && this->ISP_powered_on )

Unaligned Read

LDR             X11, [X11]
CMP             X11, X9       <----(b)
B.LS            #0x18
LDR             X10, [X10]
LDR             W9, [X10,X9]  <----(a)
B               #0x20
MOV             W9, #0xbeef
MOVK            W9, #0xdead, lsl #16
STR             W9, [X8]

(a) X9 is user controlled (b) This is a bounds check with some member variable's value and I think it was 0x4000 on an iOS 13 iPhone 11 thus we can't use the 2 bytes 0x4141 leet number

There are some checks above (b) but like passing our leet number of choice 0x41 we can crash the kernel with an "Unaligned kernel data abort" message. This can be seen in selector 72 and 73 (AppleH10CamInUserClient::_ISP_SpmiRegRead() and AppleH10CamInUserClient::_ISP_SpmiRegWrite())

Selector 77 OOB read

This function is parses a structure I named "session_str" twice. At first it takes in an 0x34 bytes buffer from the user and starts parsing it. The first 4 bytes is the number of "Groups" in the structure. Random thoughts: If we can spray OOL ports after the strIn message buffer we can probably make this code parse those messages and leak kernel pointers in the syslog but meh.

ISP_CreateMultiCameraSession_gated

  if ( *strIn )
  {
    v8 = 0LL;
    v9 = strIn + 0x10;
    do
    {
      v10 = *(v9 - 2);
      v11 = *v9;
      v9 += 4;
      if ( v11 == 1 )
        v12 = "HardwareSync";
      else
        v12 = "NoSync";
      _os_log_internal(
        &_mh_execute_header,
        &_os_log_default,
        OS_LOG_TYPE_DEFAULT,
        "    Group=%d: ChannelMask=0x%08X SyncType=%s",
        v8++,
        v10,
        v12);
    }
    while ( v8 < *strIn );                      // no bounds check on *strIn

Selector 86 Hell

__int64 __fastcall AppleH10CamIn::ISP_RunAlgoChooseJasperPriPairIndices_gated(AppleH10CamIn *this, unsigned int camChan, mach_vm_address_t address, mach_vm_size_t length, task_t task)
{

  if ( !length )
  {
    v18 = this->field_3c0 + 0x8A8LL * camChan; //field_3c0 is a 0x3400 sized buffer from what I see and it should not contain more than 6 objects
    v14 = *(v18 + 0x1A0);
    v15 = (v18 + 0x170);
    projectionMode = this->field_CC;
    inbuf = 0LL;
    inbuflen = 0;
  }
  else{
    v7 = length;
    v8 = IOMemoryDescriptor::withAddressRange(address, length, 2u, task);
    if ( !v8 )
      _os_log_internal(
        &_mh_execute_header,
        &_os_log_default,
        OS_LOG_TYPE_DEFAULT,
        "AppleH10CamIn::%s - Error: could not create memory descriptor for update data\n",
        "ISP_RunAlgoChooseJasperPriPairIndices_gated");
    v9 = 0xE00002BDLL;                                       // we don't actually return, which causes a NULL deref if we'd simply 
    if ( !(v8->preapre)(v8, 0LL) )			     // fail the creation of the Memory Descriptor
    {
      v10 = (v8->map)(v8, 4096LL);
      if ( v10 )
      {
        v11 = (v10->getVirtualAddress)();
        if ( !v11 )
          return 3758097090LL;
        inbuf = v11;
        v13 = this->field_3c0 + 0x8A8LL * camChan; <----- integer overflow 
        v14 = *(v13 + 0x1A0);
        v15 = (v13 + 0x170);
        projectionMode = this->field_CC;
        inbuflen = v7;
        goto LABEL_9;
      }
    }
  }
  v9 = JasperAgileClocking::JasperSACIndexSelect(v14, inbuf, inbuflen, v15, projectionMode);
  _os_log_internal(
    &_mh_execute_header,
    &_os_log_default,
    OS_LOG_TYPE_DEFAULT,
    "AppleH10CamIn::%s - Called JasperSACIndexSelect with projection mode [%u]\n",
    "ISP_RunAlgoChooseJasperPriPairIndices_gated",
    this->field_CC);
  if ( v9 )
  {
    _os_log_internal(
      &_mh_execute_header,
      &_os_log_default,
      OS_LOG_TYPE_DEFAULT,
      "AppleH10CamIn::%s - PRI selection returned 0x%X\n",
      "ISP_RunAlgoChooseJasperPriPairIndices_gated",
      v9);
  }
  else
  {
    v20 = 0LL;
    v21 = 0x8A8LL * camChan + 0x174;    <----- well well well another one...
    do
    {
      _os_log_internal(
        &_mh_execute_header,
        &_os_log_default,
        OS_LOG_TYPE_DEFAULT,
        "AppleH10CamIn::%s - Selected parameter indices for bank [%d]= [%u,%u]\n",
        "ISP_RunAlgoChooseJasperPriPairIndices_gated",
        v20++,
        *(this->field_3c0 + v21 - 4),
        *(this->field_3c0 + v21));
      v21 += 8LL;
    }
    while ( v20 != 4 );
    v9 = 0LL;
  }
  return v9;
}
__int64 __fastcall JasperAgileClocking::CreateFList2PllArray(__int64 a1, unsigned int *inbuf, unsigned int inbuflen, _QWORD *a4, _DWORD *a5)
{
  __int64 v5; // x8
  __int64 v11; // x24
  _DWORD *v12; // x0
  __int64 v13; // x8
  __int64 v14; // x11
  __int64 v15; // x9
  _DWORD *v16; // x11
  __int64 v17; // x11
  int v18; // w13
  __int64 v19; // x15
  unsigned int v20; // w16
  int v21; // w17
  int v22; // w16
  __int64 v23; // x16
  _DWORD *v24; // x17

  v5 = 0xE00002C2LL;
  if ( a4 && a5 )
  {
    v11 = inbuflen;
    v12 = operator new[](20LL * inbuflen); <-- inbuflen is user controllable
    if ( v12 )
    {
      *v12 = 0;
      v13 = *(a1 + 0x440);
      if ( inbuf )
        v14 = *inbuf;
      else
        v14 = 0LL;
      LODWORD(v15) = 0;
      v16 = (v13 + 24 * v14);  <--- v14 is user controllable
      v12[2] = v16[5];
      v12[4] = 0;

You can crash the kernel through this method in many ways iirc I had two different pocs for carshing at different locations. There are many integer overflows deep inside as well and the no return thing is pretty funny heh. Although field_3c0 is inited once at boot, the array size is very big and we can make our index pretty big too so I think if you can go very far in kernel memmory and if your stars are aligned you can probably corrupt some sprayed object but again idk if this is possible.

You said OOB?

    if ( *(user_buf__ + 0x34) )
    {
      v40 = 0LL;
      do
      {
        v41 = *&v238[8 * v40];
        if ( v41 )
        {
          if ( !v31 || (*(**(v15 + 0x1260) + 0x110LL))() )
          {
            LOBYTE(v32) = 1;
            (*(*v41 + 0x90LL))(v41, 1LL);
            (*(**(v15 + 0x228) + 0x90LL))();
            v42 = *&v239[8 * v40];
            (*(*v42 + 224LL))(v42, 2LL);
            (*(*v42 + 40LL))(v42);
            v43 = *&v240[8 * v40];
            IOSurface::complete(v43);
            IOSurface::deviceUnlockSurface(v43, 0);
            (v43->release)(v43);
          }
          if ( (*(**(v15 + 4704) + 272LL))() )
            (*(**(v15 + 0x1260) + 264LL))();
          user_buf__ = user_buf_;
        }
        ++v40;
      }
      while ( v40 < *(user_buf__ + 0x34) ); <-- user controllable
    }

set custom index at 0x98 and 0x9C to be anything non zero in selector 42 and in same way 0x34 and 0x38 for selector 41 AppleH10CamIn::ISP_GeneralProcess_Generic_gated() and AppleH10CamIn::ISP_GeneralProcess_gated()

Ending Notes

Another one lacking bounds check was ISP_PPMAdmissionCheck_gated() which was later on calling an assert so it's pretty much a meh thing but still. Are there more bugs tho? No definitely not - said my AI based sekure code auditor. Some notes on this driver: A11-A13 use this driver on A14 they use AppleH13Cam but from reversing it seemed like a copy paste of this one but with 1 extra external method iirc. These bugs have been made public bc Umaru Chan wanted that, so talk with her instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment