πŸ”’
There are new articles available, click to refresh the page.
Today β€” 27 October 2021Research - Companies

Use-After-Free in Voice Control: CVE-2021-30902 Write-up

27 October 2021 at 05:53
Use-After-Free in Voice Control: CVE-2021-30902 Write-up

By: 08Tc3wBB

Voice Control is a powerful feature introduced by Apple in iOS 13 and macOS Catalina. It acts as a substitute for all the touch gestures on the screen, letting you interact with the device using your voice to tap, swipe, type, and more.

com.apple.SpeechRecognitionCore.speechrecognitiond Crashes

com.apple.SpeechRecognitionCore.speechrecognitiond is a system XPCService process that handles voice control.Β 

During an investigation of ZecOps Mobile XDR / Mobile DFIR, we discovered a series of crashes that appears intriguing:

Exception Type:Β  EXC_BAD_ACCESS (SIGBUS)
Exception Subtype: EXC_ARM_DA_ALIGN at 0x0074616f6c460003

Exception Type:Β  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x2000002400000000 -> 0x0000002400000000Β 

Exception Type:Β  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x00000000100c02d8

Mobile Device Investigation Analysis

Not all crashes are the same, but they all have a similar pattern. All crashes occur after some libdispatch.dylib calls.Β 

With this clue, we went on and investigated the cause of this crash.

We’re going to explain two of the most typical cases. Both have occurred when the user is toggling the voice control switch at different timings.

We will attach a POC that demonstrates an unexpected multithread issue, proving that even when the developer uses an optimized thread management library such as Grand Central Dispatch (GCD) dispatch queues, which are already considered safe from multi-threading perspective. The chance of race condition still exists, capable of causing memory corruption and leading to code execution.

Following shows two of the most typical cases:

Race Condition Case 1: When the user turns VoiceControl off

The dispatch queue β€œRDAudioBufferQueue” is created when the device is actively processing audio data. An AVSoundInput class instance has been passed to this thread to provide the input data through context data. Due to insufficient consideration of thread safety, when the user decides to turn off the voice control feature, the context data may get released early in another queue β€œRDMainQueueβ€œ, which leads to a Use-After-Free (UAF).

There is actually a function dealing with the audio format conversion that is executed between _dispatch_call_block_and_release and <PC Corruption>. It didn’t show in the backtrace because it used the β€œbr” instruction that doesn’t save the return address in the stack.Β 

Below is the pseudo-code of the function:

(1) Inside _addRecordedSpeechSampleData:length: method, It’s trying to invoke a function pointer stored in *( *(context_data + 48) + 16), normally it will execute EARCSpeechRecognitionAudioBufferAddAudioSamples. However, if the user decides to turn off voice control, the context_data will be released in another thread, as shown below:

The problem is the lack of a lock to ensure that RDAudioBufferQueue will exit before context_data is released. The heap memory in *(context_data + 48) could be released early and reoccupied by other data, which led to Program Counter (PC) corruption.

Race Condition Case 2: When the user turns VoiceControl on

RDMainQueue may randomly occur memory corruption on different objects. The above example is that the XPC connection object was released before use, and Use-After-Free causes the thread to crash.

RDMainQueue is used as a multi-purpose general queue. Various callbacks throw tasks into this queue, including accepting and handling xpc requests, reporting audio data feedback and taking action, nested calling was frequently involved.. All these tasks are submitted to RDMainQueue through dispatch_async, and they seem to be correct in the order of calling.Β 

How does a Use-After-Free happen if the use and release of XPC connection objects are all assigned to be processed in the same queue, in the correct order ?

The answer is that dispatch_async does not guarantee the blocks to be executed in the same order it gets called!Β 

Some developers may not be aware of this behavior of dispatch_async.

The following POC demonstrates the potential threat of using dispatch_async even on a same queue:

dispatch_sync is safer as if you replace all dispatch_async to dispatch_sync, the above code will run flawlessly.

dispatch_async brings the convenience of supporting nested calls. However, for the sake of thread safety, developers better to implement additional checks to ensure that the blocks are executed in the required order.

When the user frequently turns on and off the voice control switch, the busy operation of adding queues will mess up the order, which may still use an object after it’s released.

Triggering of the Crash

You can trigger this Use-After-Free while on the lock screen, following these steps:

1. Press and hold the side button to activate Siri.

2. Say β€œTurn Off Voice Control”, a window of voice control switch should appear.

Β 3. Switch on/off Voice Control repeatedly. There is some trick to trigger the crash more reliably.

Instead of using Siri, you can also just go to Settings -> Accessibility -> Voice Control

After turning on Voice Control, an icon will appear on the left upper corner, and it first appears as grey, then it will turn blue. The trick to find the best timing is to turn off the voice control right before the icon turns to blue.

  • There are no more articles
❌