The Apple Lossless Audio Codec (ALAC) is an audio coding format developed by Apple Inc. in 2004 for lossless data compression of digital music. After initially keeping it proprietary, in late 2011 Apple made the codec open source. Since then, the ALAC format has been embedded in many non-Apple audio playback devices and programs, including Android-based smartphones, and Linux and Windows media players and converters.
The open source ALAC decoder contains serious vulnerabilities. Apple keeps updating the proprietary version of the decoder and fixing security issues, but the shared code has not been patched since 2011. Many third-party vendors use the Apple-supplied code as the basis for their own ALAC implementations, and it’s fair to assume that many of them do not maintain the external code.
We discovered that MediaTek and Qualcomm, the two largest mobile chipset makers, ported the vulnerable ALAC code into their audio decoders, which are used in more than half of all smartphones worldwide. The ALAC issues we found could be used by an attacker for RCE on a mobile device through a malformed audio file. In addition, an unprivileged Android app can use these vulnerabilities to escalate its privileges and gain access to media data and user conversations.
Our goal was not to find all the projects that integrate the ALAC decoder, but we easily found several popular Ubuntu packages in the Universe repository that are also based on the vulnerable ALAC code and can be targeted by an attacker for RCE on an Ubuntu machine.
In this study, we focus on mobile devices.
Open Media Acceleration (OpenMAX or OMX) is the set of C-language programming interfaces that provides abstractions useful for multimedia processing.
On Android devices, the Stagefright media playback engine integrates OpenMAX to recognize and use custom hardware-based multimedia codecs.
Figure 1: OpenMAX in Android media.
While Android provides built-in software codecs for common media formats, a hardware manufacturer can add an OpenMAX codec to decode/encode a specific one.
All media codecs presented on the device are listed in the /vendor/etc/media_codecs.xml file. According to the OpenMax specification, the codec name and content type must be declared for each codec.
Figure 2: Built-in software codecs.
An OpenMAX codec is a dynamic library that implements the corresponding decoding/encoding logic. The relationship table between the codec name and the library name is built into the OpenMAX Core library /vendor/lib/libOmxCore.so. On MediaTek devices, the /vendor/etc/mtk_omx_core.cfg configuration file contains this table in text format.
Figure 3: Core configuration.
Both MediaTek and Qualcomm provide custom OpenMAX decoders for the ALAC format. The ALAC declaration is shown in Figure 4, where the first line refers to MediaTek devices and the second line to those belonging to Qualcomm.
Figure 4: ALAC decoder declaration.
/vendor/lib/libMtkOmxAlacDec.so is the OpenMAX ALAC library on MediaTek devices and /vendor/lib/libOmxAlacDecSw.so is the library on Qualcomm. Media service /vendor/bin/hw/[email protected] loads the ALAC library when requested by an Android app, and then calls it to decode the supplied frames.
A malicious .m4a audio file can be used to attack a device even when played in a safe app based on the Android media framework. In addition, a malicious app can use a harmful frame to attack the privileged [email protected] service.
Requesting frame decoding from the app
The Android framework provides the android.media.MediaCodec class to access low-level media codecs.
We can create the ALAC decoder by using its name.
The configure method can be used to tune the decoder. A Codec-specific Data (csd-0) array allows us to set the frame length and bit depth parameters that we want to control in order to exploit the vulnerabilities.
To pass an arbitrary frame to the decoder for processing:
The Android app does not require any permissions to initiate decoding. To attack the media service, all we need to do is to prepare a malformed frame that causes the vulnerability.
The ALAC vulnerabilities
A quick look at the libMtkOmxAlacDec.so library showed that it is more likely based on the Shairport source code than on the code published by Apple. In fact, both sources are quite similar and have the same security issues.
The MtkOmxAlacDec::InitAlacDecoder method is responsible for initializing the ALAC decoder based on the csd-0 information provided by the app or included in the audio file header. The method calls the alac_init function, which fills an internal object with the audio parameters and allocates working buffers to store the decoded data.
The setinfo_max_samples_per_frame field of the alac object is initialized with the frame length (the first DWORD of the csd-0), and the setinfo_sample_size field is initialized with the bit depth.
The frame length times 4 of the heap memory is allocated as the outputsamples_buffer_a buffer. No integer overflow check is performed. In the 32-bit media server, if the provided frame length is greater than or equal to 0x40000000, the wrong amount of memory is allocated.
The MtkOmxAlacDec::DecodeAudio method is responsible for decoding the audio frame. It calls the alac_decode_frame function passing the alac object, the decoding frame, and an output buffer for decoded data as arguments.
The variable outputsamples is the number of samples to decode. As you can see, it is initialized with the setinfo_max_samples_per_frame at the beginning of the function, which is the maximum possible value of samples per frame. However, this variable can be corrected by the actual number of samples, the value of which is encoded in the frame itself. There are no validations associated with the outputsamples, so an invalid number could be provided. For example, in the frame in Figure 5, the number of samples is 0x41414141.
Figure 5: Malformed ALAC frame.
Several code snippets like the one shown below are implemented in the alac_decode_frame function to decode the frame data.
As you can see, outputsamples * setinfo_sample_size bits are decoded from the input frame into the outputsamples_buffer_a buffer, the size of which is setinfo_max_samples_per_frame * 4. We control all the involved values: the outputsamples, the setinfo_sample_size, the setinfo_max_samples_per_frame, and the decoding content.
For a heap data leak, we set the outputsamples and the setinfo_max_samples_per_frame to be larger than the input frame. In this case, the contents of the heap after the frame buffer are “decoded” to the outputsamples_buffer_a, which is then copied to the output buffer.
To overwrite the heap, we set the setinfo_max_samples_per_frame to be smaller than the input frame. In this case, the data is decoded outside the outputsamples_buffer_a buffer as determined by what we set in the outputsamples.
In Figure 6, you can see the crash dump caused by the malformed frame shown in Figure 5. The test device is the Xiaomi Redmi Note 9T 5G (MediaTek MT6853 Dimensity 800U 5G chipset) with MIUI Global 22.214.171.124 OS.
Figure 6: Crash dump of MediaTek’s ALAC decoder.
All of the described vulnerabilities can be exploited as they provide both read and write primitives.
The ALAC decoder implemented by Qualcomm has exactly the same issues as the MediaTek’s decoder.
The OpenMAX libOmxAlacDecSw.so library is a wrapper over the libAlacSwDec.so, which is based on the source code shared by Apple.
The ALACDecoder::Init method allocates the mMixBufferU buffer to store the decoded data. The buffer size is 4 times the frame length specified in the csd-0 and controlled by the attacker.
The ALACDecoder::Decode method decodes ALAC frames. Again, there is no verification of the number of samples provided in the frame.
Depending on the numSamples and the size of the input frame, the mMixBufferU buffer can be overflowed with the input frame or filled with leaked data.
In Figure 7, you can see the crash dump of Qualcomm’s ALAC decoder. The test device is the Sony Xperia XZ Premium.
Figure 7: Crash dump of Qualcomm’s ALAC decoder.
We discovered several vulnerabilities in the Apple lossless audio codec that are relevant for smartphones with MediaTek and Qualcomm chipsets. Two thirds of all smartphones sold in 2021 are vulnerable.
The issues we found could be used by an attacker for RCE on a mobile device via a malicious audio file, or for LPE from an unprivileged Android application. The attacker could gain access to user conversations and stored media.
MediaTek assigned CVE-2021-0674 and CVE-2021-0675 to the ALAC issues. The vulnerabilities were already fixed and published in the December 2021 MediaTek Security Bulletin. Qualcomm released the patch for CVE-2021-30351 in the December 2021 Qualcomm Security Bulletin.