愛伊米

MediaTek 音訊 DSP 中的漏洞分析

MediaTek 音訊 DSP 中的漏洞分析

MediaTek系統級晶片(SoC) 已嵌入全球約 37% 的智慧手機和物聯網裝置中,包括來自小米、Oppo、Realme、Vivo等高階手機。

MediaTek SoC,包括最新的 Dimensity 系列,包含一個特殊的 AI 處理單元 (APU) 和音訊數字訊號處理器 (DSP),以提高媒體效能並降低 CPU 使用率。APU 和音訊 DSP 都具有定製的 Tensilica Xtensa 微處理器架構。Tensilica 處理器平臺允許晶片製造商使用自定義指令擴充套件基本 Xtensa 指令集,以最佳化特定演算法並防止它們被複制。

研究人員對MediaTek音訊 DSP 韌體進行了逆向工程,儘管其操作碼和處理器暫存器具有獨特的安全防護,但他們還是發現了幾個可從 Android 使用者空間訪問的漏洞。

透過與原始裝置製造商 (OEM) 合作伙伴庫中的漏洞相關聯,研究人員發現的MediaTek安全問題可能會導致 Android 應用程式的本地許可權升級。成功利用 DSP 漏洞可能允許攻擊者監聽使用者對話或隱藏惡意程式碼。

透過 Android 攻擊音訊 DSP 的方法

研究人員研究的目標是找到一種透過 Android 攻擊音訊 DSP 的方法。首先,研究人員需要了解執行在應用處理器 (AP) 上的 Android 如何與音訊處理器進行通訊。顯然,必須有一個驅動程式等待來自 Android 使用者空間的請求,然後使用某種處理器間通訊 (IPC),將這些請求轉發給 DSP 進行處理。

使用基於MT6853晶片組的小米紅米Note 9 5G智慧手機作為測試裝置,作業系統為 MIUI Global 12。5。2。0 (Android 11 RP1A。200720。011)。

由於裝置上呈現的媒體相關驅動程式很少,所以不難找到負責AP和DSP之間通訊的驅動程式。

媒體驅動程式

研究人員對 /dev/audio_ipi 驅動程式感興趣。

在供應商分割槽中對驅動程式名稱進行簡單搜尋,即可找到MediaTek API庫/vendor/lib/hw/audio。primary。mt6853。so。該庫匯出AudioMessengerIPI示例,其中包含sendIpiMsg方法,該方法可用於向音訊DSP傳送IPI訊息。研究人員使用這個庫來探索 Android 使用者空間和核心之間的通訊流程。在研究人員的 PoC 程式碼中,研究人員直接處理驅動程式 ioctls,無需額外包裝。

/dev/audio_ipi 驅動程式中定義了以下 ioctls:

傳送訊息前,必須使用AUDIO_IPI_INIT_DSP ioctl對DSP韌體進行初始化。

研究人員可以使用以下簡單的函式來開啟和初始化驅動程式:

MediaTek 音訊 DSP 中的漏洞分析

在 DSP 端,有幾個獨立的訊息處理程式,稱為任務場景。每個任務場景都有自己獨特的功能範圍。例如,電話任務控制語音增強。AUDIO_IPI_LOAD_SCENE ioctl 用於在 DSP 上載入任務場景。任務場景ID是IPI訊息的必填引數。

有三種不同的 ioctl 用於向音訊 DSP 傳送 IPI 訊息。不同之處在於與訊息關聯的有效載荷資料的傳輸方式。可能的選擇是:

將有效載荷作為訊息的一部分傳輸 (AUDIO_IPI_SEND_PAYLOAD)。有效載荷大小限制為 0xE0 位元組;

透過註冊為在 AP 和 DSP 之間進行通訊的共享記憶體 (AUDIO_IPI_SEND_DRAM) 傳輸載荷;有效載荷大小受共享區域大小的限制;

不要傳輸有效載荷 (AUDIO_IPI_SEND_MSG_ONLY);

IPI 訊息具有以下結構:

MediaTek 音訊 DSP 中的漏洞分析

重要的領域是:

task_scene——DSP任務場景ID;

data_type——有效載荷型別,如果有效載荷欄位包含與訊息關聯的資料,則設定為 1。如果有效載荷欄位包含有關共享區域的資訊,則設定為 2;

msg_id ——訊息 ID;

param1 和 param2——訊息引數,通常 param1 包含有效載荷大小。

因此,研究人員可以完全控制從 Android 使用者空間傳輸的訊息。透過 task_scene 和 msg_id 欄位定位 DSP 處理程式,並透過 param1、param2 和有效載荷欄位為其提供研究人員的資料。

現在就可以處理共享記憶體了, AUDIO_IPI_REG_DMA ioctl 可用於請求 DSP 驅動程式在 AP 和 DSP 之間共享的專用直接訪問儲存器 (DMA) 中分配一個區域。實際上,分配了兩個記憶體區域:一個用於從AP傳輸資料到DSP任務場景,另一個用於反向傳輸資料。DSP 驅動程式在呼叫 AUDIO_IPI_SEND_DRAM ioctl 時使用這些區域傳輸訊息有效載荷並接收結果。

AUDIO_IPI_REG_DMA ioctl 需要具有以下結構的物件作為引數:

研究人員透過 a2d_size 和 d2a_size 欄位控制分配區域的大小。

Android 核心日誌為研究人員提供了有關預留 DMA 的資訊:

基本虛擬地址- 0xffffff800b000000;

基本物理地址:0x7d940000;

大小- 0x200000;

當研究人員為任務場景分配共享區域時,也會記錄 DMA 中的相應偏移量。

Android 核心日誌

任務場景的共享區域的物理地址(計算為DMA的基本物理地址+共享區域的偏移量)在裝置上是持久的。

以下函式可用於透過 DMA 傳送帶有資料傳輸的 IPI 訊息:

MediaTek 音訊 DSP 中的漏洞分析

/dev/audio_ipi 驅動程式不直接與音訊 DSP 通訊。相反,它透過將訊息新增到 SCP 佇列將 IPI 訊息轉發到系統控制處理器 (SCP)。音訊DSP韌體註冊SCP排程器以接收來自SCP的音訊IPI訊息。

逆向過程

韌體映象

研究人員知道如何向音訊 DSP 傳送 IPI 訊息,下一步是在 DSP 韌體中找到此類訊息的處理程式。

音訊 DSP 在小米出廠更新中透過單獨的 audio_dsp。img 映象檔案呈現。獲取映象的另一種方法是從根裝置轉儲 /dev/block/platform/bootdevice/by-name/audio_dsp 分割槽。

映象檔案具有專有結構,但可以輕鬆重建。在研究人員的測試裝置上,DSP 映象包含九個分割槽。

MediaTek 音訊 DSP 中的漏洞分析

audio_dsp。img 結構

cert1 和 cert2 分割槽是 DER 格式的證書,用於驗證 hifi3 分割槽的完整性。hifi3_a_dram 分割槽是音訊韌體使用的動態記憶體。在初始狀態下,它幾乎是空的。hifi3_a_iram和hifi3_a_sram分割槽是自定義FreeRTOS的程式碼和資料。

每個分割槽都有一個標頭,用於儲存該分割槽的大小和名稱。標頭以神奇的 0x88168858 開頭,可用於快速定位檔案中分割槽的開頭。圖 4 顯示了 hifi3_a_dram 標頭。

hifi3_a_dram 標頭

hifi3_a_dram 分割槽的標頭和資料大小分別為 0x200 和 0x8000,研究人員可以輕鬆剪下hifi3內容。

仔細看看 hifi3_a_sram,分割槽以 0x400 零位元組開始。所以這裡沒有特殊的檔案格式。研究人員正在處理原始資料。接下來的 0x37F8 位元組似乎是指向記憶體的指標,主要位於 0x56000000 地址之後,從位元組 0x3BF8 開始是 Xtensa 程式碼。

IDA Pro 7。6 支援 Tensilica Xtensa 架構。研究人員在IDA中開啟hifi3_a_sram分割槽,基地址為0x56000000。

研究人員使用這個簡單的指令碼將前導原始位元組識別為指標(雙字):

現在研究人員有成千上萬個指向程式碼和資料的指標。但是研究人員如何處理程式碼呢?Xtensa 操作碼的長度可變,IDA 不知道如何進行。

研究人員首先嚐試編寫一個指令碼來查詢函式的開頭並嘗試反彙編。這是可能的,因為大多數函式都從分配堆疊的入口操作碼開始。但它在這裡效果不佳,因為有太多 IDA 不知道的自定義操作碼。反彙編遇到未知操作碼時會卡住。研究人員得到的只是如下片段:

MediaTek 音訊 DSP 中的漏洞分析

最終,研究人員找到了另一個很好的解決方案。研究人員使用 Xtensa SDK 來幫助 IDA。

HiFi DSP 軟體開發工具鏈可以從 tensilicatools。com 網站免費下載。XtDevTools 是安裝包的一部分。研究人員使用 ~/xtensa/XtDevTools/install/tools/RI-2020。5-linux/XtensaTools/bin/xt-objdump 工具來建立 hifi3 分割槽的物件轉儲。這樣研究人員就轉儲了hifi3_a_sram:

物件轉儲包含反彙編的 Xtensa 程式碼,來看看IDA收到的指令:

如你所見,xt-objdump 工具的 hifi3_ss_spfpu_7 核心比 IDA 外掛知道更多的 Xtensa 操作碼。顯然,MediaTek使用了Tensilica準備的標準音頻DSP模板作為其處理器的基礎。MediaTek添加了幾個特定的指令,但與 Tensilica 為音訊 DSP 提供的指令相比,它們的數量很少。

物件轉儲包含許多漏洞,不能作為研究的主要來源。但它可以幫助 IDA 更輕鬆地拆解 hifi3 分割槽。

Xtensa 外掛在 IDA 中由 xtensa。so 庫表示。因為要新增的指令太多,所以不容易打補丁。最好的解決方案是使用物件轉儲來查詢所有基本的 Xtensa 指令,並將反彙編作為註釋新增到任何無法識別的指令中。一個簡單的 IDA 指令碼就可以完成這項工作。在下圖中,你可以看到應用轉儲後 IDA 導航欄的外觀。幾乎所有的程式碼塊都被識別。

IDA 導航欄

反彙編後的程式碼如下所示:

大多數韌體功能都包含用於記錄除錯資訊的程式碼。日誌訊息包括當前函式的名稱。MediaTek給了研究人員自描述的函式名和快速搜尋程式碼中函式的能力。

研究人員以與 hifi3_a_sram 相同的方式拆解了 hifi3_a_iram 分割槽。hifi3_a_dram 和 hifi3_a_iram 的基地址分別為 0x4FFB0000 和 0x4FFE0000。

FreeRTOS

既然找到了研究音訊DSP韌體的方法,就來看看它的內容。

MediaTek 音訊 DSP 作業系統是 FreeRTOS 的改編版本。MediaTek使用了第三方核心,並在其上實現了音訊和訊息邏輯。

作業系統在啟動時會建立許多音訊任務,並將它們與場景 ID 相關聯。研究人員可以在 create_all_audio_task 函式中找到所有支援的任務和場景 ID。以下任務在研究人員的測試裝置上執行:

MediaTek 音訊 DSP 中的漏洞分析

每個音訊任務由一個包含指向 recv_message 函式的指標的任務物件表示。當新的 IPI 訊息到達時,SCP 訊息排程程式呼叫此函式。IPI 訊息作為第二個引數傳遞給函式。

recv_message 函式正是研究人員正在尋找的。這是音訊任務開始處理從 Android 端傳送的 IPI 訊息的地方。快速檢視程式碼後,研究人員看到除了電話呼叫、解除安裝、控制器和守護程序之外,大多數任務都使用相同的 task_common_recv_message 函式。畢竟,只有接下來的五個函式解析 IPI 訊息,這是研究人員可以搜尋漏洞的地方:

MediaTek 音訊 DSP 中的漏洞分析

研究人員手動檢查了這些功能,發現了幾個可用於從 Android 攻擊 DSP 的漏洞。

CVE-2021-0661、CVE-2021-0662 和 CVE-2021-0663

AUDIO_DSP_TASK_MSGA2DSHAREMEM 訊息處理程式中的經典堆溢位

此漏洞與所有常見的音訊 DSP 任務有關。在處理 ID 為 6 (AUDIO_DSP_TASK_MSGA2DSHAREMEM) 的 IPI 訊息時,task_common_task_loop 函式會將訊息載荷複製到公共任務物件的 atod_share 欄位中。訊息 param1 用作要複製的位元組數。省略了 param1 不大於 atod_share 欄位大小的檢查。因此,當載荷大小大於0x20位元組時,載荷會覆蓋atod_share之後的記憶體。

下面的呼叫send_ipi_dma在Android端覆蓋DSP記憶體垃圾和導致崩潰:

init_share_mem_core 函式中的經典堆溢位

當接收到ID為7的IPI訊息時,守護任務的task_auddaemon_task_loop函式呼叫init_share_mem_core函式。init_share_mem_core 使用 param1 作為要複製的位元組數將訊息有效載荷複製到內部 audio_dsp_dram 緩衝區。該函式檢查 param1 是否小於 0xE0 位元組,但 audio_dsp_dram 大小為 0x20 位元組, 0xC0 位元組可以被覆蓋。

要使用受控值修復 DSP 堆,研究人員可以傳送攜帶有效載荷的 IPI 訊息作為訊息的一部分:

Android 核心日誌確認了該漏洞:

audio_dsp_hw_open_op 函式中的陣列索引驗證不正確

在處理 ID 為 0x203 (AUDIO_DSP_TASK_PCM_PREPARE) 的 IPI 訊息時,task_common_task_loop 函式呼叫 get_audiobuf_from_msg 從 param2 定址的物理記憶體中提取音訊緩衝區。接下來,將此緩衝區作為引數傳遞給作為 audio_dsp_hw_open_op 的包裝器的 audio_dsp_hw_open 函式。audio_dsp_hw_open_op 函式將此音訊緩衝區複製到靜態陣列。音訊緩衝區中偏移量 0x54 處的欄位用作陣列索引。沒有索引值的溢位檢查。因此,研究人員可以提供任意索引,用受控值覆蓋陣列後面的一部分記憶體。

要擁有音訊緩衝區,研究人員可以透過共享 DMA 區域將 IPI 訊息傳送到 DSP,並將 param2 指向有效載荷所在的記憶體。正如研究人員之前所展示的,共享 DMA 區域的物理地址永久存在於裝置上。

以下 PoC 程式碼會重新啟動研究人員的測試裝置:

請注意,get_audiobuf_from_msg 函式也不驗證 param2。在 param2 中使用任何不合適或空的地址都會使 memcpy 函式中的 DSP 崩潰:

尋找一種從非特權應用程式攻擊 Android HAL 的方法

現在研究人員知道如何透過 /dev/audio_ipi 驅動程式從 Android 攻擊音訊 DSP。不幸的是,無特權的 Android 應用程式以及 adb shell 沒有與此驅動程式通訊的許可權。SELinux 僅允許從 factory、meta_tst 和 mtk_hal_audio 上下文訪問 audio_ipi_device 物件。攻擊者需要找到一種方法來利用 MediaTek 硬體抽象層 (HAL) 從 mtk_hal_audio 上下文下訪問 DSP 驅動程式。

在尋找攻擊 Android HAL 的方法時,研究人員發現了 MediaTek 為除錯目的實施的幾個危險的音訊設定。第三方 Android 應用程式可以濫用這些設定來攻擊 MediaTek Aurisys HAL 庫。

音訊硬體引數

Android 文件指出 AudioManager 提供對音量和鈴聲模式控制的訪問。Android 應用程式可以繫結音訊服務,然後使用 AudioManager 的 setParameters 方法來配置硬體。

裝置製造商可以新增他們自己的音訊設定並跟蹤他們的更改。MediaTek 提供專有引數來配置 Aurisys 庫。在研究人員的測試裝置上,/vendor/lib/hw/audio。primary。mt6853。so 庫負責處理MediaTek新增的音訊引數。在下圖中,你可以看到 setParameters 字串引數的可接受格式。

MediaTek音訊引數

引數字串包含以下資訊:

處理命令的目標子系統,它可以是 HAL 或 DSP;

aurisys 場景;

標識受影響的 HAL 庫的命令項;

命令字串,研究人員找到了八個支援的命令;

該值實際上是命令的引數;

/vendor/etc/aurisys_config。xml 和 aurisys_config_hifi3。xml 檔案定義了所有支援的 aurisys 場景和命令項。

例如,以下引數可用於啟用語音處理資訊的日誌記錄:

大多數支援的命令在資訊洩漏方面對研究人員來說很有趣。但是研究人員只想關注 PARAM_FILE 命令,它允許研究人員設定與特定 Aurisys HAL 庫相關的配置檔案的位置。

例如,非特權 Android 應用程式可以透過設定以下引數來自定義 OEM 提供的 libfvaudio。so HAL 庫:

Aurisys 庫在提供時解析配置檔案。

注意,裝置製造商通常不關心正確地驗證配置檔案,因為非特權使用者無法使用這些檔案。但在研究人員的例子中,他們控制著配置檔案。HAL 配置成為攻擊媒介。格式錯誤的配置檔案可用於使 Aurisys 庫崩潰,從而導致 LPE。

研究人員已經準備了一個針對小米裝置上的 libfvaudio。so HAL 庫的攻擊示例,但出於安全原因,研究人員無法分享詳細資訊。

為了緩解所描述的音訊配置問題,MediaTek決定在 Android 的釋出版本中刪除透過 AudioManager 使用 PARAM_FILE 命令的功能,且漏洞被命名為 CVE-2021-0673。

參考及來源:https://research。checkpoint。com/2021/looking-for-vulnerabilities-in-mediatek-audio-dsp/