Hello everyone. Thank you for attending this talk. I'm Slava. I'm a security researcher at CheckPoint. Security research is my daily work. 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. Let's begin with a question. Do you know how many processors are on your mobile phone? The answer is many. 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. Snapdragon product tiers are differentiated by scalable computing resources for the CPU, GPU and DSP. 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. These are modem DSP, known as baseband audio DSP, compute DSP, and sensor DSP. In this research, I turned my attention to ADSP and CDSP subsystems. 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. On some devices, such as the Sony Xperia XZ, only the ADSP processor is responsible for all these tasks. But on other devices, such as the Pixel 4, these tasks are shared between ADSP and CDSP. Let's take a look at the communication scheme between an Android application and a DSP running library. FasterPC is a Qualcomm proprietary RPC mechanism used to enable remote code function calls between application processor, where Android is run, and DSP. On Android side, user mode process initiates the remote invocation. In our case, an Android application calls one of the stub functions in its native code. Stub is auto-generated code that converts the function call to an RPC message. Generally, the stub code is compiled as a separate native library. The stub code loads libADSP-RPCSO and libCDSP-RPCSO built-in libraries to invoke Android drivers. DSP-RPC drivers send the queued message to the DSP side through the shared memory channel, and then wait for the response. On DSP side, a framework presented by the FasterPC shell binary dequeues the messages and dispatches them for processing by a skeleton. And again, skeleton is auto-generated library that unmashes parameters and calls the target method in the object library. The object library is some logic provided by Qualcomm or OEMs and designed to run on a DSP. Who can run their own code on DSP? Any third-party developer can implement its own DSP library. Because the Hexagon SDK, which is responsible for compiling C++ code into Hexagon bytecode, is publicly available. But it's impossible to run a third-party library on DSP. For security reasons, DSP is licensed for programming by OEMs and code running on the DSP is signed by Qualcomm. Who manages the DSP? It's Qt, a Qualcomm proprietary multi-threaded real-time operating system. Integrity of the Qt is trusted by the trust zone. 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. For each Android process initiating the remote invocation, Qt creates a separate faster PC shell process on the DSP. The DSP architecture provides different protection domains, PD. Kernel PD has access to all memory of all domains. Guest OS PD has access to the memory of its own PD and memory of the user PD and some system registers. User PD has access only to its own memory. Skeleton and object libraries, as well as the fast RPC shell, are running in the user PD. The stub code provided by Qualcomm or OEMs can be skipped from the fast RPC chain. As was mentioned, libADSP-RPC and libCDSP-RPC libraries are responsible for communication with DSP-RPC drivers. Each library exports two major functions. Remote handle open function opens a remote session between the client on application processor and new fast RPC shell process on the DSP. The skeleton library name is provided as the first argument. Remote handle invoke function is able to invoke methods exported by the skeleton library. Using these two functions, an Android application can request to execute any skeleton method without using a stub code. Now we have enough information to state the downgrade vulnerability. DSP libraries are signed and cannot be patched. However, any Android application can bring a signed by Qualcomm skeleton library in its assets and then open a remote session. The library will be successfully loaded on the DSP because its signature is correct. 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. Even if the patched skeleton library already exists on the device, it is possible to load the old version of this library. Any DSP code fix can be simply bypassed by an attacker. 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. This means that a vulnerability discovered in one of OEM libraries compromises all Snapdragon-based Android devices. The major goal of the research was to find a way to execute custom code on a DSP bypassing Qualcomm's signature. To do so, we had to discover and exploit a vulnerability in a DSP-running library. DSP libraries are proprietary hexagon ELFs. The easiest way to instrument a hexagon executable is to use the open-source QUIC emulator, QEMU. Hexagon instruction set support was added in QEMU only in the end of 2019. We fixed a lot of bugs to be able to run real DSP libraries in the user mode of the emulator. To fast leaps on Ubuntu PC, we used American Fuzzy Loop, AFL, in combination with QEMU. A skeleton library is primarily a library, and we had to prepare a simple program, a scale loader, that loads and invokes the one. Moreover, most skeleton libraries widely use DSP framework and system calls. Our simple program cannot handle such requests. Therefore, we had to load the cured OS on the emulator before execution of the REST call. 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. That's it. The IFR permutates the content of a data file and triggers execution of Run-ELF-PBM on the emulator. QEMU returns the code coverage matrix to the AFL after execution of the test case. On this slide, you can see the data format that we used to fuzz skeleton libraries. The first word is the second argument of the remote handle invoke function. The index on the invoked method, number of input and number of output arguments are encoded there. Next several words we take as the size of arguments, then we expect to see a value of input arguments. We were surprised by the fuzzing result. Crashes were found in all DSP libraries that we choose to fuzz. Besides, most issues were discovered exactly in skeleton libraries. This means that hexagon SDK reduces vulnerable code. Hexagon SDK automatically generates stub and scale code for marshalling and unmarshalling of function arguments. Let's take a look at an example of such code. Stub and scale code based on interface definition language modus, IDL modus, prepared by the developer. Here you can see an example of the IDL declaration of two functions in the neural network library, HexagonNN. A vulnerable code will be generated for both of them. HexagonNN SMP print function passes an input-output buffer argument to the DSP. In the stub code this buffer will be split into two separate buffers, the input and the output. The value of the buffer length will also be duplicated and therefore serialized twice. The scale function copies the input of the output buffer before calling an objects function. The size of data to be copied is one of the transmitted buffer lengths. An attacker controls this value. All verification checks can simply be bypassed by using a negative input buffer length. Typecasting to the signed int type on checking buffer boundaries is a bug leading to heap overflow. 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. Dozens of DSP skeleton libraries pre-installed on Android smartphones are vulnerable due to serious bugs in the SDK. So, we discovered many vulnerabilities. Let's exploit one of them. LibFastCV, a DSP-scale SO library, can be found on most Android devices. In this example, I used the lib extracted from the Sony Xperia XZ Premium device. A malicious Android application can cause this lib to crash by providing crafted arguments to the remote handling function. The 3F method allows us to read and write everything that we want within the other space of the DSP process. It's enough to implement an exploit and execute an unsigned payload in the user protection domain. Ok, we got code execution. What can we do with it? We can crash the DSP, we can hide malicious code, we can try to access camera sensors and more. Besides, now we can communicate with secured drivers. The next step of the research is to attack the Qt-privileged domains from the user protection domain. And Qt drivers are the entry points for this. QtOS implements its own device driver model, named Qt Driver Invocation, QD. Like POSIX, Qt device drivers operate with higher privileges than user code. Dozens of Qt drivers can be found in the Qt binary. libQtA library, which is part of Hexagon SDK, contains the Qt infrastructure. FasterPC shell is linked statically with the library. QD provides a simple driver invocation API with the ability to access a device driver based only on the driver name. Actually, only Qt QD handle invoke macro is the necessary user visible API. It's responsible for all generic driver operations. The Qt QD open is just a special case of this macro. 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. Qt drivers were not included by Qualcomm in the run.elf.pdn version of Qt. Therefore, we had to patch the run.elf file. What did we do? 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. Our simple QD exec program is responsible for calling the driver invocation function by its address. First of all, any failure in Qt drivers can be used to reboot the mobile device. 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. For research purposes, we exploited one of the discovered vulnerabilities in glink-qt-driver. Along with the user-pd exploit, it allows us to run a custom code in the context of the guest OS protection memory. Now I'll show a simple demo to prove the full attack chain. The payload will return a DSP internal data inaccessible from application processor. The device is a Pixel 4. Here you can see that using a DB shell, I'm executing some tool which can be used by any Android application. This tool will trigger chain of vulnerabilities and return some inaccessible from application processor data. For example, Qt OS data signal. After that, I'm going to control the phone and, for example, I just reboot. Instead of a conclusion, I just want to note that hexagon ADSP and CDSP subsystem are very promising areas for security research. The DSP is accessible from Android application, has access to interesting data for an attacker, and has many security issues. Thank you for your attention.