相關議程精華紀錄聲明
以下議程精華紀錄由 AI 協助整理與重構,內容僅供參考,實際細節請以講者原始演講與官方資料為準。
破解 Pixel 8:利用未公開的 DSP 漏洞繞過 MTE 防護
講者
Billy(Jheng Bing Jhong)、Pan Zhenpeng(Peter)
Billy 與 Peter 都是 STAR LABS SG 的 Principal Researcher,長期專注於 Android / iOS / Linux / VM 等行動與系統資安研究,曾在 HITCON、DEF CON、POC、Zer0Con 等研討會發表。
議程重點
1. 背景與動機
- 研究目標鎖定 Android 14 的 Pixel 8,這台機器上幾乎把主流防護都開好開滿:
- PAN / PXN(防止 kernel 亂用 user space 記憶體)
- UAO(限制對 user access helper 的寫入)
- PAC(指標簽章,抵禦 ROP)
- MTE(Memory Tagging Extension)
- KASLR、stack/heap 初始化強化、list 完整性檢查、slab free-list randomization… 等
- 在本地提權攻擊中,永遠需要一個「攻擊面」作為起點;不同攻擊面影響範圍不同:
- Universal:例如 Linux kernel
unix socket、binder、pipe buffer - Chipset-specific:如 Mali / Qualcomm GPU driver、Qualcomm DSP
- Vendor-specific:Samsung 自家 NPU、GPU、KNOX / Defex 等
- Model / module-specific:只存在於特定機型或個別模組
- Universal:例如 Linux kernel
- 本場研究的漏洞屬於 Pixel 專屬 DSP 模組 的攻擊面,可視為 module-specific exploit:
- Pixel 使用 Google 自家 DSP(簡稱 GXP),2022 才在 Pixel 7 引入
- 沒有公開文件、沒有 toolchain、也沒有既有漏洞研究
- 過去已有許多 GPU / NPU / DSP 相關漏洞研究(Mali、Qualcomm GPU / DSP、Samsung NPU 等),團隊希望把這些經驗「複製」到 GXP 上,看看是否也存在類似問題。
2. 主要問題 / 挑戰
- GXP 完全沒文件、沒工具鏈
想分析 DSP firmware 卻沒有 ISA 文件、沒有開發工具,只能從 kernel driver + firmware binary 逆向。 - 攻擊面被 SELinux 嚴格管控
- 一般
untrusted_appcontext 不能直接 open GXP device,卻被允許發送某些ioctl - 顯示一定有中介 server 代為開啟 device → 必須先搞清楚這條路徑
- 一般
- 漏洞屬性是「理論上可行」,但不確定實際能利用
- driver 中出現一個「讓 DMA 寫入 CPU read-only 記憶體」的可能性
- 但 如果沒有任何 DSP 端 API 真的會去寫那塊 memory,這就只是紙上談兵
- 在強化的 Android 環境中串成完整 exploit chain 很難
- MTE、KASLR、SELinux、各種硬化 config 都在
- 要從 app → system service → kernel module → root shell,中間每一步都可能被擋
- 如何穩定控制高權限的 system service(camera provider)
- 從 app 看不到目標 service 的 PID
- 在隔離環境下難以直接對特定 process 下手
- 要找到一種「大致猜到 PID,再強迫它重啟並載入惡意 library」的方法
3. 技術方法 / 解決方案
3-1 攻擊面盤點:為什麼選 GXP DSP?
- Pixel 中除了常見 GPU 外,還有幾個 Google 自家 driver:
- Pixel HTPU、Pixel GXP、LWIS 等
- Edge TPU 過去就有公開漏洞(例如 race condition 導致 kernel memory 損壞),證明這類協同處理器 driver 不是沒問題。
- GXP:
- 新、文件少、沒有公開研究
- 又是影像處理 pipeline 中核心元件,Google Camera 等系統 app 都會用
→ 在防護都很新而且開滿的 Pixel 8 上,GXP 成為很有吸引力的攻擊面。
3-2 先找得到攻擊面:從 SELinux policy 入手
- 檢查 SELinux policy 後發現:
untrusted_appcontext 可以對 GXP 做 ioctl,但 不能 open 裝置節點- 代表:必須透過某個「中介 server」幫忙 open 後,把 FD 傳給 app
- 逆向相關 library / service:
- 在 policy 中發現
edge_tpu_app_server之類的 server context - 逆向
libedge_tpu_client、libgxp.so等,看到像get_dsp_fd()這種 function - 確認流程:app → client lib → edge_tpu app server → 打開 GXP device → 傳回 FD
- 在 policy 中發現
- 結論:
只要能在「被列入 whitelist 的 app / 簽章」中執行我們的 code,就能觸碰到 GXP 攻擊面。
3-3 漏洞本體:GXP mapping 的「write read-only」問題
- 透過
ioctl(GXP_MAP_BUFFER, …)可以走到 kernel 中的gxp_mapping_create():- 驅動會根據 user 傳進來的參數:
- 利用
find_extend_vma()找到被 import 的 user VMA - 從這個 VMA 取得屬性,設定
folio_flags(read / write…) - 但
mapping_dir(DMA 方向)卻直接抄 user 傳入的dir不做檢查
- 接著:
mapping_dir會被用來設定 DSP MMU 上這塊 memory 的屬性- 如果 user 傳
DMA_BIDIRECTIONAL,DSP 端就會認為這塊 memory 是「可讀可寫」
- 於是出現關鍵問題:
CPU 這邊把某塊記憶體映成 read-only,
但 GXP driver 可以被騙,
把同一塊物理頁在 DSP 的 MMU 上映成 read-write。
- 這就提供了 「write read-only memory」primitive:
- 只要 GXP 有任何 API 會對這塊 buffer 寫東西,就等於繞過 CPU 端的唯讀保護。
3-4 第一次嘗試:模擬 firmware(放棄)
- 步驟:
- 在 driver 中找到載入 firmware 的程式(透過 device tree resource 找到物理位址,
devm_ioremap()映射到 kernel) - 用自寫內核模組 / BPF 把這片 memory dump 出來
- 丟進 IDA 逆向,確認裡面有 mailbox / ring buffer 等 DSP 相關符號
- 想用 QEMU 之類的工具模擬 CPU + 跑 firmware,進一步找「寫 memory 的 handler」
- 在 driver 中找到載入 firmware 的程式(透過 device tree resource 找到物理位址,
- 實際遇到的坑:
- QEMU 不支援這顆 DSP 的指令集
- 很多系統暫存器(MSR/MRS 類)不符合手冊行為
- 沒符號、架構又陌生 → 逆向成本超高
- 結果:
幾天後直接放棄,改走「重放攻擊(replay attack)」路線。
3-5 第二次嘗試:Replay Attack + Frida 動態插樁
- 先找「誰在用 GXP」:
- 從 SELinux policy & 實作觀察得知:
- Google Camera、YouTube Music 等 whitelist app 會使用 GXP
- 選擇最常見、預設內建且一定會調用的 Google Camera 作為觀察目標
- 在 Google Camera process 裡:
- 找到一個 share library:
libgxp.so - 裡面可以看到類似 OpenCL 的介面:
create_device、create_buffer、enqueue… 等 - 推測:這就是 GXP 版的「使用者態 API」。
- 找到一個 share library:
- 使用 Frida:
- 利用
Interceptor.attach()hook 目標 process 的ioctl - 同時列舉
libgxp.so的所有 exported functions,一一加上 hook - 記錄實際拍照 / 開啟 Camera 時,GXP 使用的 call flow與各種參數
- 利用
- 收穫:
- 在
libgxp.so中找到一個關鍵高階 API:
類似gxp_copy_open_named_library_from_buffer()的函式 - 透過這個 API,可以觸發之前找到的「可疑 mapping code」,而且 確認 GXP 會對 buffer 寫入內容。
- 在
- PoC 實作:
- 在 user space 建立一個 read-only 映射頁面,初始化成 0
- 把這塊頁面 import 給 GXP,並強塞
DMA_BIDIRECTIONAL - 呼叫上述 copy 函數
- 回到 CPU 端檢查這頁記憶體 → 發現被覆寫成
0xAA
⇒ 實證:GXP 確實可以寫 CPU 端的 read-only 頁面。
3-6 Google 的修補方式
- 修補後的 driver:
- 從 host VMA 正確取得
gup_flags(get_user_pages的 flag) - 將其轉換為內部
gci_flags - 以
gci_flags為唯一來源,設定 DMA/MMU 屬性
- 從 host VMA 正確取得
- 整體 flow:
Host address → VMA → GUP flags → GCI flags → MMU mapping
→ user 想用dir欺騙 mapping_dir 已經行不通。
3-7 Exploit Chain:從 write read-only 到 kernel module & root
- 原本想走 Dirty Pipe 式路線(但被 SELinux 卡住)
- Dirty Pipe 的經典做法:
改寫只讀檔(如libc.so或 config),劫持高權限 process → 寫入 kernel module →modprobe載入 → 關 SELinux → root shell。 - 問題:
- Dirty Pipe 只需要一般 syscall,沒特殊權限
- 本漏洞則 必須能「隱身地」操作 GXP device
→ 在init/system_server這種 context 中 拿不到 GXP 使用權限
- Dirty Pipe 的經典做法:
- 改走 Camera provider 路線
- 觀察 SELinux policy:
android.hardware.camera.provider這個 service- 可以 open / ioctl GXP device
- 也可以 open / mmap 某些 vendor 檔案(library)
- 目標:
劫持 camera provider,讓它在重啟時載入我們控制的 library。
- 如何強迫 camera provider 重啟?(不知道 PID 的情況下)
- 特性:
- Camera provider 是開機早期就啟動的 system daemons 之一
- 開機後這類 daemon 的 PID 會落在一個相對小且穩定的範圍
- 作法:
- 由我們控制的 context(有能力殺 process)去 遍歷這個 PID range,逐一送
kill - 大部分被殺的是 system daemon,會被
init自動拉起 - 在這個過程中也會順便把 camera provider 幹掉,迫使它重啟
- 由我們控制的 context(有能力殺 process)去 遍歷這個 PID range,逐一送
- 限制:
- 如果系統已跑很久、camera provider 中途 crash 過再重啟,PID 可能跳到很大範圍,這種方法就不穩定。
- Library Hijacking & 多階段 payload
- Stage 1:從 app → write read-only
- 使用 GXP 漏洞,把某個「camera provider 會在啟動時載入的 library」(例如負責 logging 的
liblog類型)改成帶有我們 loader 的版本 - 強迫 camera provider 重啟 → 下次啟動時就會載入被我們修改的 library → 取得 camera provider context 下的程式碼執行
- 使用 GXP 漏洞,把某個「camera provider 會在啟動時載入的 library」(例如負責 logging 的
- Stage 2:在 camera provider 內部再利用 write read-only
- 再次使用 write read-only primitive,寫入兩類 payload:
- 修改
modprobe相關設定(或特定 config),讓 kernel 在需要載入 module 時會去讀我們控制的位置 - 在某個路徑放入「惡意 kernel module」的 binary(reverse shell + 關 SELinux)
- 修改
- 利用擁有足夠權限的 process 觸發
modprobe - kernel 讀到被改寫的路径,載入我們的 module
- 再次使用 write read-only primitive,寫入兩類 payload:
- Stage 3:kernel module
- 被載入後:
- 關閉 SELinux
- 建立 reverse shell,連回攻擊者的 server,取得 root shell
- 被載入後:
- 為什麼 exploit 要跑 5 分鐘?
- GXP 端提供的 copy 函數行為類似
strcpy:- 遇到
0x00就停止
- 遇到
- 但 shellcode / payload 總是含有大量 0 bytes
- 不能一次 copy 完整 buffer,不然會斷在第一個 0
- 只好 一個 byte 一個 byte 重複呼叫,慢慢寫入
- 加上:
- 整個 chain 有很多 stage
- 每一次 DSP ↔ CPU 都要做 memory synchronize
→ 全部疊加起來,完整 exploit 流程大約要跑五分鐘左右。
4. 實驗成果 / 攻擊流程摘要
- 目標環境
- 裝置:Google Pixel 8
- 系統:Android 14
- 安全機制:MTE / KASLR / 各種 kernel hardening 啟用
- 攻擊成果
- 從一個安裝在手機上的 app 開始
- 透過 GXP DSP 漏洞取得 write read-only primitive
- 劫持
android.hardware.camera.provider服務 - 植入惡意 kernel module,載入後關 SELinux
- 取得 root shell(reverse shell 回連攻擊者電腦)
- 漏洞修補 & 負責任通報
- 2023 年中發現漏洞並開始開發 exploit
- 2023/9 報給 Google
- Google 要求提供「可重現的 source-based PoC」,而非單純 binary
- 2023/11 Google 對外宣佈相關 bug bounty
- 2024 Q1 左右完成修補並發佈 patch(CVE 編號當時尚未公開)
- 講者透露這個漏洞日後還會出現在另一條 exploit chain 的研究中
5. 限制與未來方向
- 漏洞影響面狹窄
- 只影響具備 Pixel GXP DSP、且具備相同 driver 實作的裝置
- 更偏向「model / module-specific」的攻擊
- Exploit 本身較脆弱
- 依賴 PID range 的特徵來強迫 camera provider 重啟
- 需 5 分鐘以上執行時間,實務上偏向「高價值目標」才值得這樣操作
- MTE 的防護邊界
- MTE 主要防範 緩衝區溢位 / use-after-free 等記憶體破壞
- 對於:
- DMA 屬性錯誤
- 協同處理器 MMU 管理邏輯 bug
→ 完全無能為力
- 未來可能方向
- 更系統地審視各家協同處理器(DSP / NPU / ISP / baseband)的 DMA 及 MMU 流程
- 在 OS 層加入 runtime consistency check(例如:檢查 DMA 屬性是否與 VMA 權限一致)
- 安全審查流程中,把「vendor 自研 IP / driver」當成一級攻擊面,而不是附屬。
💡 我的觀察
-
1. 防禦做得越好,攻擊面就越往「灰暗角落」擠
- 當 kernel、system server、常見 driver 都被鋪滿 mitigations 之後,攻擊者就會開始鑽進:
- 各種協同處理器(DSP / NPU / ISP)
- vendor / model 專屬 driver
- 這場研究非常典型:不是從 Linux 主線 bug 下手,而是從 Pixel 自家 GXP DSP 打進去。
- 對企業與 OEM 來說,安全審查不能只看「主 SoC + Android 原生部分」,所有自研模組都要列入 Threat Model。
- 2. MTE 不是萬靈丹,它擋的是「類型」,不是「所有 0day」
- 很多人看到 MTE 會直覺覺得「那本地提權是不是要絕跡了?」
這場議程很直接地給出:No。 - 只要攻擊從一開始就不是典型的 buffer overflow / UAF,而是:
- DMA 屬性錯誤
- 邏輯漏洞
- 權限邊界錯配
→ MTE 根本不會出手。 - 所謂的「bypass MTE」很多時候不是什麼花式繞過,而是 選擇一條 MTE 原本就管不到的路線。
這對 defender 的啟示是:導入硬體防護時,一定要清楚「它保護的是哪一塊」,不要把其他風險當作已解決。
- 很多人看到 MTE 會直覺覺得「那本地提權是不是要絕跡了?」
- 3. Replay 攻擊是 Closed-source 環境下非常實用的研究方法
- 在沒有文件、沒有 toolchain 的 DSP 上,講者沒有硬幹完整逆向,而是:
- 利用 SELinux policy 找出誰在用 device
- 透過 Frida 直接對現實世界「怎麼用 driver」做 trace
- 把 production app 的實際行為當作「官方 SDK」來複用
- 這種 replay + hook 的手法對紅隊非常有參考價值:
不一定要搞懂所有細節,只要能重放系統自己怎麼用,就足以構造 exploit。 - 相對地,藍隊也應該把「system app 對 kernel driver 的 ioctls」視為關鍵觀測點,
不尋常的參數模式可能就是 exploit 在跑。
- 4. 從企業角度:kernel module 仍然是致命後門
- 這條 chain 最終還是落在 任意載入 kernel module、關 SELinux、開 root shell。
- 對企業裝置或高價值標的來說:
- 降低或監控
modprobe行為 - 嚴格限制自訂 module 的存在(甚至關掉 module support)
- 對 boot chain、system image 做完整性保護
仍然是非常關鍵的防線。
整體來說,這場議程展示的是:
在「幾乎所有主流防護都打開」的 Pixel 8 上,攻擊者依然可以透過一顆幾乎沒人碰過的 DSP,一路打到 kernel root。
對做防禦的人而言,這提醒我們:真正的攻擊面,常常躲在你以為「只是加速影像處理的小 IP」裡面。
