WEBVTT

00:01.410 --> 00:02.990
Hello everyone.

00:02.990 --> 00:05.070
Thank you for attending this talk.

00:05.510 --> 00:06.550
I'm Slava.

00:06.550 --> 00:09.090
I'm a security researcher at CheckPoint.

00:09.430 --> 00:12.710
Security research is my daily work.

00:12.930 --> 00:24.890
Today I'm going to show how an Android application can attack the digital signal processor of a mobile device and thereby gain privileges and denial-of-service capabilities.

00:29.600 --> 00:31.880
Let's begin with a question.

00:31.880 --> 00:36.360
Do you know how many processors are on your mobile phone?

00:36.400 --> 00:38.640
The answer is many.

00:38.660 --> 01:00.240
As a single Snapdragon system on a chip embedded in Pixel, Samsung, Xiaomi, LG, OnePlus, Sony and other devices may include multiple CPU cores, an Adreno graphic processor unit, a Snapdragon wireless module, a Hexagon digital signal processor, and Spectro image signal processor.

01:00.240 --> 01:09.680
Snapdragon product tiers are differentiated by scalable computing resources for the CPU, GPU and DSP.

01:09.680 --> 01:23.580
The lowest tiers might contain only a single Hexagon DSP, whereas the premium tier contains up to four Hexagon DSP processors dedicated for specific use cases.

01:24.300 --> 01:33.020
These are modem DSP, known as baseband audio DSP, compute DSP, and sensor DSP.

01:33.040 --> 01:40.620
In this research, I turned my attention to ADSP and CDSP subsystems.

01:41.420 --> 01:57.280
ADSP and CDSP processors are intended for such cool tasks as processing of audio and voice data, computer vision, machine learning calculations, camera streaming, artificial intelligence, etc.

01:57.280 --> 02:07.860
On some devices, such as the Sony Xperia XZ, only the ADSP processor is responsible for all these tasks.

02:07.860 --> 02:17.680
But on other devices, such as the Pixel 4, these tasks are shared between ADSP and CDSP.

02:18.680 --> 02:26.100
Let's take a look at the communication scheme between an Android application and a DSP running library.

02:27.620 --> 02:41.220
FasterPC is a Qualcomm proprietary RPC mechanism used to enable remote code function calls between application processor, where Android is run, and DSP.

02:41.220 --> 02:47.140
On Android side, user mode process initiates the remote invocation.

02:47.140 --> 02:53.630
In our case, an Android application calls one of the stub functions in its native code.

02:53.630 --> 03:01.990
Stub is auto-generated code that converts the function call to an RPC message.

03:01.990 --> 03:08.450
Generally, the stub code is compiled as a separate native library.

03:08.690 --> 03:18.870
The stub code loads libADSP-RPCSO and libCDSP-RPCSO built-in libraries to invoke Android drivers.

03:18.870 --> 03:30.150
DSP-RPC drivers send the queued message to the DSP side through the shared memory channel, and then wait for the response.

03:31.510 --> 03:43.950
On DSP side, a framework presented by the FasterPC shell binary dequeues the messages and dispatches them for processing by a skeleton.

03:43.950 --> 03:54.370
And again, skeleton is auto-generated library that unmashes parameters and calls the target method in the object library.

03:54.370 --> 04:02.810
The object library is some logic provided by Qualcomm or OEMs and designed to run on a DSP.

04:05.070 --> 04:08.250
Who can run their own code on DSP?

04:08.650 --> 04:13.350
Any third-party developer can implement its own DSP library.

04:13.950 --> 04:23.130
Because the Hexagon SDK, which is responsible for compiling C++ code into Hexagon bytecode, is publicly available.

04:23.510 --> 04:28.850
But it's impossible to run a third-party library on DSP.

04:28.930 --> 04:39.030
For security reasons, DSP is licensed for programming by OEMs and code running on the DSP is signed by Qualcomm.

04:41.060 --> 04:43.760
Who manages the DSP?

04:43.760 --> 04:49.960
It's Qt, a Qualcomm proprietary multi-threaded real-time operating system.

04:49.960 --> 04:53.980
Integrity of the Qt is trusted by the trust zone.

04:53.980 --> 05:09.800
Qt executable binary, different for ADSP and CDSP, is assigned and split into several files in the same way as any other trusted application on Qualcomm devices.

05:10.740 --> 05:20.280
For each Android process initiating the remote invocation, Qt creates a separate faster PC shell process on the DSP.

05:20.640 --> 05:26.320
The DSP architecture provides different protection domains, PD.

05:26.540 --> 05:31.020
Kernel PD has access to all memory of all domains.

05:31.020 --> 05:39.780
Guest OS PD has access to the memory of its own PD and memory of the user PD and some system registers.

05:40.580 --> 05:45.000
User PD has access only to its own memory.

05:45.820 --> 05:53.200
Skeleton and object libraries, as well as the fast RPC shell, are running in the user PD.

05:55.650 --> 06:02.310
The stub code provided by Qualcomm or OEMs can be skipped from the fast RPC chain.

06:03.010 --> 06:13.430
As was mentioned, libADSP-RPC and libCDSP-RPC libraries are responsible for communication with DSP-RPC drivers.

06:13.810 --> 06:18.570
Each library exports two major functions.

06:18.570 --> 06:29.490
Remote handle open function opens a remote session between the client on application processor and new fast RPC shell process on the DSP.

06:29.970 --> 06:34.150
The skeleton library name is provided as the first argument.

06:34.150 --> 06:41.770
Remote handle invoke function is able to invoke methods exported by the skeleton library.

06:41.930 --> 06:52.330
Using these two functions, an Android application can request to execute any skeleton method without using a stub code.

06:53.730 --> 06:58.730
Now we have enough information to state the downgrade vulnerability.

06:59.010 --> 07:03.610
DSP libraries are signed and cannot be patched.

07:03.610 --> 07:13.810
However, any Android application can bring a signed by Qualcomm skeleton library in its assets and then open a remote session.

07:13.910 --> 07:19.730
The library will be successfully loaded on the DSP because its signature is correct.

07:21.070 --> 07:34.050
The fact that there is no version check of loading skeleton libraries opens the possibility to run a very old skeleton lib with known one-day vulnerabilities on the DSP.

07:34.050 --> 07:43.730
Even if the patched skeleton library already exists on the device, it is possible to load the old version of this library.

07:44.070 --> 07:50.070
Any DSP code fix can be simply bypassed by an attacker.

07:51.070 --> 08:04.990
Due to the lack of leads of the skeleton libraries permitted for the device, it is possible to run a library intended for one device, for example, Chinese Xiaomi, on any other device, for example, Samsung.

08:05.010 --> 08:15.390
This means that a vulnerability discovered in one of OEM libraries compromises all Snapdragon-based Android devices.

08:17.710 --> 08:26.830
The major goal of the research was to find a way to execute custom code on a DSP bypassing Qualcomm's signature.

08:27.030 --> 08:34.650
To do so, we had to discover and exploit a vulnerability in a DSP-running library.

08:36.270 --> 08:40.270
DSP libraries are proprietary hexagon ELFs.

08:40.390 --> 08:47.610
The easiest way to instrument a hexagon executable is to use the open-source QUIC emulator, QEMU.

08:48.190 --> 08:55.790
Hexagon instruction set support was added in QEMU only in the end of 2019.

08:56.030 --> 09:03.050
We fixed a lot of bugs to be able to run real DSP libraries in the user mode of the emulator.

09:03.970 --> 09:11.490
To fast leaps on Ubuntu PC, we used American Fuzzy Loop, AFL, in combination with QEMU.

09:11.490 --> 09:21.270
A skeleton library is primarily a library, and we had to prepare a simple program, a scale loader, that loads and invokes the one.

09:21.630 --> 09:28.430
Moreover, most skeleton libraries widely use DSP framework and system calls.

09:28.430 --> 09:31.750
Our simple program cannot handle such requests.

09:32.010 --> 09:39.870
Therefore, we had to load the cured OS on the emulator before execution of the REST call.

09:39.870 --> 09:55.950
The easiest way to do so is not to use a real cured OS, but its light version, Run-ELF-PBM, adopted by Qualcomm for execution on a hexagon simulator, and included in the hexagon SDK.

09:56.570 --> 09:58.190
That's it.

09:58.190 --> 10:07.830
The IFR permutates the content of a data file and triggers execution of Run-ELF-PBM on the emulator.

10:07.830 --> 10:14.270
QEMU returns the code coverage matrix to the AFL after execution of the test case.

10:15.590 --> 10:22.210
On this slide, you can see the data format that we used to fuzz skeleton libraries.

10:22.430 --> 10:28.750
The first word is the second argument of the remote handle invoke function.

10:28.830 --> 10:36.750
The index on the invoked method, number of input and number of output arguments are encoded there.

10:36.750 --> 10:46.150
Next several words we take as the size of arguments, then we expect to see a value of input arguments.

10:47.270 --> 10:51.050
We were surprised by the fuzzing result.

10:51.050 --> 10:56.090
Crashes were found in all DSP libraries that we choose to fuzz.

10:56.090 --> 11:02.210
Besides, most issues were discovered exactly in skeleton libraries.

11:02.210 --> 11:07.290
This means that hexagon SDK reduces vulnerable code.

11:08.970 --> 11:18.530
Hexagon SDK automatically generates stub and scale code for marshalling and unmarshalling of function arguments.

11:18.650 --> 11:22.710
Let's take a look at an example of such code.

11:25.150 --> 11:35.510
Stub and scale code based on interface definition language modus, IDL modus, prepared by the developer.

11:35.510 --> 11:44.670
Here you can see an example of the IDL declaration of two functions in the neural network library, HexagonNN.

11:44.670 --> 11:48.650
A vulnerable code will be generated for both of them.

11:50.350 --> 11:58.870
HexagonNN SMP print function passes an input-output buffer argument to the DSP.

11:58.870 --> 12:06.510
In the stub code this buffer will be split into two separate buffers, the input and the output.

12:06.510 --> 12:14.370
The value of the buffer length will also be duplicated and therefore serialized twice.

12:15.870 --> 12:24.690
The scale function copies the input of the output buffer before calling an objects function.

12:24.690 --> 12:31.290
The size of data to be copied is one of the transmitted buffer lengths.

12:31.310 --> 12:33.690
An attacker controls this value.

12:33.690 --> 12:41.010
All verification checks can simply be bypassed by using a negative input buffer length.

12:41.010 --> 12:51.090
Typecasting to the signed int type on checking buffer boundaries is a bug leading to heap overflow.

12:52.070 --> 13:08.070
To summarize, the automatically generated code injects vulnerabilities into the libraries of Qualcomm, OEMs and all other third-party developers who use the Hexagon SDK.

13:08.070 --> 13:18.570
Dozens of DSP skeleton libraries pre-installed on Android smartphones are vulnerable due to serious bugs in the SDK.

13:20.050 --> 13:23.190
So, we discovered many vulnerabilities.

13:23.190 --> 13:26.230
Let's exploit one of them.

13:27.410 --> 13:33.910
LibFastCV, a DSP-scale SO library, can be found on most Android devices.

13:33.910 --> 13:41.110
In this example, I used the lib extracted from the Sony Xperia XZ Premium device.

13:41.390 --> 13:50.150
A malicious Android application can cause this lib to crash by providing crafted arguments to the remote handling function.

13:51.550 --> 14:00.230
The 3F method allows us to read and write everything that we want within the other space of the DSP process.

14:00.230 --> 14:09.110
It's enough to implement an exploit and execute an unsigned payload in the user protection domain.

14:10.230 --> 14:12.970
Ok, we got code execution.

14:12.970 --> 14:14.710
What can we do with it?

14:14.710 --> 14:23.470
We can crash the DSP, we can hide malicious code, we can try to access camera sensors and more.

14:23.590 --> 14:28.370
Besides, now we can communicate with secured drivers.

14:29.490 --> 14:38.430
The next step of the research is to attack the Qt-privileged domains from the user protection domain.

14:38.430 --> 14:43.330
And Qt drivers are the entry points for this.

14:45.230 --> 14:53.430
QtOS implements its own device driver model, named Qt Driver Invocation, QD.

14:53.430 --> 15:00.730
Like POSIX, Qt device drivers operate with higher privileges than user code.

15:00.730 --> 15:06.650
Dozens of Qt drivers can be found in the Qt binary.

15:07.670 --> 15:15.310
libQtA library, which is part of Hexagon SDK, contains the Qt infrastructure.

15:15.310 --> 15:19.710
FasterPC shell is linked statically with the library.

15:22.370 --> 15:32.430
QD provides a simple driver invocation API with the ability to access a device driver based only on the driver name.

15:32.610 --> 15:41.250
Actually, only Qt QD handle invoke macro is the necessary user visible API.

15:41.290 --> 15:45.570
It's responsible for all generic driver operations.

15:45.910 --> 15:50.090
The Qt QD open is just a special case of this macro.

15:53.890 --> 16:05.100
To fuzz Qt drivers on Ubuntu PC, we use the same combination of Hexagon QMU and AFM, as for fuzzing of user-mode DSP libraries.

16:06.390 --> 16:13.850
Qt drivers were not included by Qualcomm in the run.elf.pdn version of Qt.

16:13.850 --> 16:18.110
Therefore, we had to patch the run.elf file.

16:18.110 --> 16:20.330
What did we do?

16:20.330 --> 16:36.550
We appended program segments of Qt.elf from a real device and redirected malloc and memcpy kernel functions used by Qt drivers to their user-mode implementation.

16:37.610 --> 16:46.730
Our simple QD exec program is responsible for calling the driver invocation function by its address.

16:48.830 --> 16:55.730
First of all, any failure in Qt drivers can be used to reboot the mobile device.

16:55.850 --> 17:06.970
For example, each of the lines of this code will cause a DSP panic and can be used for a denial-service attack on the device.

17:06.970 --> 17:14.810
For research purposes, we exploited one of the discovered vulnerabilities in glink-qt-driver.

17:14.870 --> 17:25.170
Along with the user-pd exploit, it allows us to run a custom code in the context of the guest OS protection memory.

17:27.190 --> 17:32.150
Now I'll show a simple demo to prove the full attack chain.

17:32.150 --> 17:40.370
The payload will return a DSP internal data inaccessible from application processor.

17:40.370 --> 17:43.510
The device is a Pixel 4.

17:56.510 --> 18:09.790
Here you can see that using a DB shell, I'm executing some tool which can be used by any Android application.

18:09.790 --> 18:20.590
This tool will trigger chain of vulnerabilities and return some inaccessible from application processor data.

18:20.590 --> 18:24.150
For example, Qt OS data signal.

18:24.330 --> 18:29.970
After that, I'm going to control the phone and, for example, I just reboot.

18:39.640 --> 18:51.580
Instead of a conclusion, I just want to note that hexagon ADSP and CDSP subsystem are very promising areas for security research.

18:51.580 --> 19:01.900
The DSP is accessible from Android application, has access to interesting data for an attacker, and has many security issues.

19:03.500 --> 19:05.560
Thank you for your attention.

