當DMA想“越獄”:IOMMU怎么硬核攔截?
在計算機的底層架構中,DMA(直接內(nèi)存訪問)技術原本旨在提升數(shù)據(jù)傳輸效率,讓硬件設備能繞開 CPU,直接與內(nèi)存高速交互,極大地加快了諸如磁盤存取、圖像處理等場景中的數(shù)據(jù)吞吐速度 。然而,這一特性卻被別有用心之人利用,成為惡意攻擊的 “幫兇”,如同試圖 “越獄” 一般,突破系統(tǒng)既定的安全邊界。攻擊者借助 DMA,可通過惡意硬件接入,繞開操作系統(tǒng)常規(guī)防護,肆意讀取敏感數(shù)據(jù)、篡改內(nèi)核代碼,甚至繞過屏幕密碼,威脅用戶信息安全與系統(tǒng)穩(wěn)定。
此時,IOMMU(輸入輸出內(nèi)存管理單元)挺身而出,作為守護系統(tǒng)安全的關鍵防線,發(fā)揮硬核攔截作用。它如同一位嚴謹?shù)?“交通管制員”,對 DMA 的內(nèi)存訪問行為進行精細管控,重新映射設備地址,限定其可觸及的內(nèi)存范圍,讓惡意的 DMA “越獄” 企圖無處遁形。接下來,就讓我們深入這場安全攻防的幕后,一探 IOMMU 如何憑借精妙設計,成功抵御 DMA 的危險沖擊 。
Part1IOMMU是什么?
1.1 IOMMU概述
IOMMU,全稱 Input/Output Memory Management Unit,即輸入輸出內(nèi)存管理單元 ,從名字就可以看出,這是一種內(nèi)存管理單元(MMU),主要負責將具有直接存儲器訪問(DMA)能力的 I/O 總線連接至主內(nèi)存。我們可以把它想象成一個 “翻譯官”,在計算機的硬件世界里,承擔著至關重要的地址轉換工作。
在計算機系統(tǒng)中,CPU 訪問內(nèi)存時,內(nèi)存管理單元(MMU)會把 CPU 可見的虛擬地址轉換為物理地址。與之類似,IOMMU 的作用是將設備可見的虛擬地址(在 IOMMU 的語境中,也被稱為設備地址或 I/O 地址)映射到物理地址。簡單來說,當設備想要訪問內(nèi)存時,它給出的地址可能是一個虛擬的 “想法”,而 IOMMU 會將這個 “想法” 翻譯成內(nèi)存能夠理解的物理地址,從而實現(xiàn)設備與內(nèi)存之間的有效溝通。
除了地址轉換,部分 IOMMU 還具備內(nèi)存保護功能,就像是給內(nèi)存區(qū)域加上了一把 “安全鎖”,能夠防止故障設備或者惡意設備對內(nèi)存進行錯誤訪問,確保系統(tǒng)的穩(wěn)定性和安全性。
1.2 IOMMU 的由來
在計算機發(fā)展的早期階段,硬件系統(tǒng)的結構相對簡單,設備在訪問內(nèi)存時采用的是直接物理尋址方式。那時候,設備可以直接訪問物理內(nèi)存,雖然這種方式簡單直接,但也帶來了一系列的問題。
隨著計算機技術的發(fā)展,計算機系統(tǒng)中的設備種類和數(shù)量不斷增加,這些設備在進行內(nèi)存訪問時遇到了一些挑戰(zhàn)。比如,早期的設備地址空間有限,像 32 位的 PCI 設備,就無法直接訪問超過 4GB 的內(nèi)存 。如果操作系統(tǒng)需要訪問超出這個范圍的內(nèi)存,就不得不采用一些復雜且低效的方法,如設置彈跳緩沖區(qū)(bounce buffer),即先將數(shù)據(jù)從高端內(nèi)存復制到設備可訪問的低端內(nèi)存區(qū)域,設備再從這里讀取數(shù)據(jù),操作完成后再把數(shù)據(jù)復制回高端內(nèi)存,這個過程大大增加了數(shù)據(jù)傳輸?shù)臅r間和系統(tǒng)開銷。
再比如,早期的設備訪問內(nèi)存時缺乏有效的內(nèi)存保護機制,一旦設備驅動程序出現(xiàn)錯誤,或者設備本身出現(xiàn)故障,就可能導致內(nèi)存數(shù)據(jù)被錯誤地讀取或寫入,甚至惡意設備可能會對系統(tǒng)內(nèi)存進行任意訪問,從而引發(fā)系統(tǒng)崩潰或數(shù)據(jù)泄露等嚴重問題。這就好比在一個沒有門禁的倉庫里,任何人都可以隨意進出并拿走或修改里面的物品,安全性完全無法保障。
為了解決這些問題,IOMMU 應運而生。它的出現(xiàn)就像是在設備和內(nèi)存之間建立了一個智能的 “中介”,解決了設備內(nèi)存訪問中的尋址限制和內(nèi)存保護缺失等問題。通過 IOMMU,設備可以訪問更大的內(nèi)存空間,并且能夠有效地保護內(nèi)存不被錯誤或惡意訪問,提高了系統(tǒng)的穩(wěn)定性和安全性。
而隨著虛擬化技術的興起,IOMMU 的重要性更是日益凸顯。在虛擬化環(huán)境中,多個虛擬機共享同一臺物理主機的硬件資源。如果沒有 IOMMU,當虛擬機中的設備進行 DMA 操作時,就可能會訪問到其他虛擬機或者宿主機的內(nèi)存空間,導致數(shù)據(jù)泄露和系統(tǒng)不穩(wěn)定。IOMMU 通過對設備地址的轉換和內(nèi)存訪問的控制,確保每個虛擬機的設備只能訪問其所屬虛擬機的內(nèi)存,為虛擬機提供了安全隔離的運行環(huán)境,使得虛擬化技術能夠更加可靠地應用于云計算、數(shù)據(jù)中心等領域。
Part2IOMMU的底層原理
IOMMU的核心思想是將物理內(nèi)存劃分為多個區(qū)域,每個區(qū)域都有一個唯一的ID。這些區(qū)域可以是連續(xù)的,也可以是不連續(xù)的。當CPU需要訪問某個內(nèi)存區(qū)域時,IOMMU會將該請求轉換為一個虛擬地址,然后將這個虛擬地址與對應的物理地址進行映射。這樣,IOMMU是DMA直接內(nèi)存訪問,即設備與內(nèi)存直接通信,而無需經(jīng)過CPU。
IOMMU的主要組成部分包括:
- MMU(Memory Management Unit):負責將物理內(nèi)存映射到虛擬地址空間。MMU通常包含一個硬件緩存,用于存儲虛擬地址到物理地址的映射關系。此外,MMU還可以實現(xiàn)一些高級功能,如內(nèi)存保護和地址轉換。
- IOMMU軟件模塊:負責管理IOMMU的設置和配置。這通常包括創(chuàng)建和管理內(nèi)存區(qū)域,以及處理來自操作系統(tǒng)的內(nèi)存訪問請求。
- 硬件支持:IOMMU需要硬件的支持才能正常工作。這包括一個支持IOMMU的CPU,以及一個能夠識別IOMMU的設備驅動程序。
2.1 DMA 重映射原理
IOMMU 的核心功能之一是 DMA 重映射,它就像是一座橋梁,連接了設備和內(nèi)存之間的地址空間。我們知道,在計算機系統(tǒng)中,內(nèi)存管理單元(MMU)通過頁表將 CPU 的虛擬地址轉換為物理地址,使得不同進程的虛擬地址空間能夠相互隔離,同時也提高了內(nèi)存的利用率 。IOMMU 在 DMA 操作中也采用了類似的機制。
設備看到的地址空間(連續(xù)):
[0x1000] [0x2000] [0x3000] [0x4000]
↓ ↓ ↓ ↓
實際物理內(nèi)存(分散):
[0xA000] [0xF000] [0xB000] [0xD000]在 IOMMU 的世界里,設備使用的地址被稱為 I/O 虛擬地址(IOVA) ,這是設備在發(fā)起 DMA 請求時所使用的地址。而 IOMMU 的任務就是將這些 IOVA 轉換為物理地址(PA),以便設備能夠正確地訪問內(nèi)存。為了實現(xiàn)這一轉換,IOMMU 使用了一種類似于 MMU 頁表的數(shù)據(jù)結構,我們可以稱之為 I/O 頁表。
當設備發(fā)起 DMA 請求時,它會將自己的 Source Identifier(包含 Bus、Device、Func,即總線號、設備號和功能號)包含在請求中。IOMMU 根據(jù)這個標識,以 RTADDR_REG(根表地址寄存器)指向空間為基地址,然后利用 Bus、Device、Func 在 Context Table(上下文表)中找到對應的 Context Entry(上下文條目) ,這個 Context Entry 實際上就是頁表首地址。找到了頁表首地址后,IOMMU 就可以利用頁表將設備請求的虛擬地址翻譯成物理地址,就像 MMU 利用頁表進行地址轉換一樣。
例如,在一個具有多個 PCI 設備的系統(tǒng)中,每個 PCI 設備都有自己的 Source Identifier。當某個 PCI 設備發(fā)起 DMA 請求時,IOMMU 會根據(jù)其 Source Identifier 在 Context Table 中找到對應的 Context Entry,進而定位到該設備專用的頁表。通過這個頁表,IOMMU 將設備請求的 IOVA 轉換為正確的物理地址,確保數(shù)據(jù)能夠準確無誤地在設備和內(nèi)存之間傳輸。
這種機制不僅解決了設備地址空間有限的問題,還為系統(tǒng)提供了內(nèi)存保護功能。因為設備只能通過 IOMMU 訪問經(jīng)過映射的物理地址,所以即使設備驅動程序出現(xiàn)錯誤,也無法直接訪問到非法的內(nèi)存區(qū)域,從而提高了系統(tǒng)的穩(wěn)定性和安全性。
2.2中斷重映射原理
除了 DMA 重映射,IOMMU 還具備中斷重映射的功能,這在虛擬化場景中尤為重要。在傳統(tǒng)的非虛擬化環(huán)境中,設備的中斷請求可以直接發(fā)送到 CPU,由操作系統(tǒng)進行處理。但在虛擬化環(huán)境下,情況變得復雜起來。當一個設備被直通給虛擬機時,它的中斷請求需要被正確地投遞到對應的虛擬機中,而不是直接發(fā)送到宿主機的 CPU,這就需要 IOMMU 來進行中斷重映射。
在現(xiàn)代計算機系統(tǒng)中,許多設備使用以 message signal 形式觸發(fā)的中斷,如 MSI(Message Signaled Interrupts)或 MSIX(Message Signaled Interrupts Extension) 。這些中斷的實現(xiàn)方式是通過向特定的地址發(fā)起一個 DMA 寫操作來觸發(fā)。IOMMU 正是通過識別這個特定的地址前綴(如 0xFEE)來判斷某個 DMA 寫操作是否是一個中斷請求。
以 PCI 或 PCIE 設備為例,在中斷重映射模式下,當設備發(fā)起 MSI 或 MSIX 中斷請求時,其 message address 和 message data 的格式會有所不同。比如,address register bit 4 需要置為 1,表示為中斷重映射模式;address register bit 3 表示的是 SubHandle Valid(SHV) ,這里強制為 1 即 SubHandle 是有效的;address register bits 19:5 表示的是 interrupt_index 的 0~14 位,bit 2 表示的是 interrupt_index 的第 15 位。這些信息用于 IOMMU 在中斷重映射表中查找對應的中斷描述符,從而確定中斷的目標虛擬機或 CPU。
再看 ioapic(I/O Advanced Programmable Interrupt Controller) ,它在系統(tǒng)中負責中斷的路由。在中斷重映射模式下,ioapic 的 redirection table entry(重定向表項)的格式也發(fā)生了變化,新增了一些字段,如 bits 49:63 對應的是 interrupt_index [14:0],bit 11 對應的是 interrup_index [15] ,bit 48 表示是否為 remapping 的中斷格式等。這些字段幫助 ioapic 在 IOMMU 的協(xié)助下,將設備的中斷請求正確地路由到目標位置。
當 IOMMU 接收到一個中斷請求時,它會根據(jù)請求中的相關信息(如 interrupt_index、SHV 等)在中斷重映射表(Interrupt Remapping Table)中查找對應的中斷描述符(Interrupt Remapping Table Entry,IRTE) 。找到 IRTE 后,IOMMU 根據(jù)其中記錄的信息,將中斷請求發(fā)送到正確的目標,可能是虛擬機中的虛擬 CPU,也可能是宿主機的特定 CPU 核心,從而實現(xiàn)了中斷在虛擬化環(huán)境中的正確投遞和處理。
中斷重映射功能確保了虛擬化環(huán)境中設備中斷的正確處理,避免了中斷混亂和錯誤投遞的問題,為虛擬機的穩(wěn)定運行提供了保障。
2.3IOMMU的主要實現(xiàn)
(1)Intel VT-d (Virtualization Technology for Directed I/O)
// Intel VT-d 功能特性
- DMA 重映射
- 中斷重映射
- 設備隔離
- 熱插拔支持(2)AMD-Vi (AMD I/O Virtualization)
// AMD-Vi 功能特性
- I/O 虛擬化
- 設備表管理
- 命令處理
- 事件日志(3) ARM SMMU (System Memory Management Unit)
// ARM SMMU 功能特性
- 流表 (Stream Table)
- 上下文描述符
- 頁表遍歷
- 故障處理Part3IOMMU的應用場景
隨著云計算和虛擬化技術的飛速發(fā)展,虛擬化環(huán)境在企業(yè)和數(shù)據(jù)中心中得到了廣泛應用。在虛擬化環(huán)境中,多個虛擬機共享同一物理硬件資源,這就對系統(tǒng)的安全性和隔離性提出了極高的要求。IOMMU 作為虛擬化技術的關鍵支撐,在保障虛擬機之間的隔離與安全方面發(fā)揮著不可或缺的作用。
在一個典型的云計算數(shù)據(jù)中心中,可能同時運行著多個不同租戶的虛擬機,每個虛擬機都承載著不同的業(yè)務應用,這些應用可能包含著租戶的敏感數(shù)據(jù)。如果沒有有效的隔離機制,一旦某個虛擬機中的 DMA 操作出現(xiàn)異?;虮粣阂饫?,就可能導致其他虛擬機的數(shù)據(jù)泄露或系統(tǒng)故障。
IOMMU 通過地址轉換和訪問控制功能,為每個虛擬機建立了獨立的內(nèi)存訪問空間 。當虛擬機中的設備發(fā)起 DMA 請求時,IOMMU 會將虛擬機的設備地址(GPA)轉換為物理地址(PA),并確保該請求只能訪問分配給該虛擬機的內(nèi)存區(qū)域。即使某個虛擬機被黑客攻擊,黑客試圖利用 DMA 操作竊取其他虛擬機的數(shù)據(jù),IOMMU 也會嚴格按照訪問權限規(guī)則,攔截非法的內(nèi)存訪問請求,從而保障了其他虛擬機的數(shù)據(jù)安全和正常運行。
假設在一個虛擬化的服務器環(huán)境中,有一臺虛擬機運行著企業(yè)的財務系統(tǒng),存儲著重要的財務數(shù)據(jù);另一臺虛擬機運行著企業(yè)的辦公自動化系統(tǒng)。如果沒有 IOMMU 的保護,當辦公自動化系統(tǒng)所在的虛擬機中存在惡意軟件,利用 DMA “越獄” 嘗試訪問財務系統(tǒng)所在虛擬機的內(nèi)存時,就可能導致財務數(shù)據(jù)泄露。而有了 IOMMU,它會對每一個 DMA 請求進行嚴格審查,一旦發(fā)現(xiàn)辦公自動化系統(tǒng)虛擬機的 DMA 請求試圖訪問財務系統(tǒng)虛擬機的內(nèi)存區(qū)域,就會立即阻止該請求,確保了財務數(shù)據(jù)的安全性和保密性 。IOMMU 在虛擬化環(huán)境中的應用,極大地提高了云計算和虛擬化系統(tǒng)的安全性和可靠性,為企業(yè)和用戶的數(shù)據(jù)安全提供了堅實的保障,推動了虛擬化技術在更廣泛領域的應用和發(fā)展。
3.1虛擬化環(huán)境
IOMMU 是設備直通 (Device Passthrough) 的基礎:
# KVM 虛擬機配置示例
<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio'/>
<source>
<address domain='0x0000' bus='0x01' slot='0x00' functinotallow='0x0'/>
</source>
</hostdev>VFIO (Virtual Function I/O) 框架
// VFIO 使用 IOMMU 實現(xiàn)設備隔離
struct vfio_group *group;
struct vfio_device *device;
// 將設備綁定到 VFIO 驅動
echo 0000:01:00.0 > /sys/bus/pci/drivers/nvidia/unbind
echo 0000:01:00.0 > /sys/bus/pci/drivers/vfio-pci/bind
// 在虛擬機中直接使用設備
qemu-kvm -device vfio-pci,host=01:00.0 ...3.2容器化和微服務
# Docker 容器使用 GPU 示例
docker run --gpus all \
--device=/dev/dri \
--security-opt apparmor:unconfined \
nvidia/cuda:11.0-base3.3安全隔離
// 防止惡意設備的 DMA 攻擊
Bad Device ─── DMA Request ──→ IOMMU ──→ Access Denied
(惡意地址) (權限檢查失敗)Part4IOMMU配置和管理
4.1系統(tǒng)啟動配置
# GRUB 配置啟用 IOMMU
# Intel 系統(tǒng)
GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt"
# AMD 系統(tǒng)
GRUB_CMDLINE_LINUX="amd_iommu=on iommu=pt"
# 更新 GRUB
sudo update-grub
sudo reboot4.2檢查 IOMMU 狀態(tài)
# 檢查 IOMMU 是否啟用
dmesg | grep -i iommu
dmesg | grep -i dmar # Intel VT-d
dmesg | grep -i amd_iommu # AMD-Vi
# 查看 IOMMU 組
find /sys/kernel/iommu_groups/ -type l
# 查看設備的 IOMMU 組
ls -la /sys/bus/pci/devices/0000:01:00.0/iommu_group4.3 IOMMU 組管理
#!/bin/bash
# 顯示所有 IOMMU 組和對應設備
for g in /sys/kernel/iommu_groups/*; do
echo "IOMMU Group ${g##*/}:"
for d in $g/devices/*; do
echo -e "\t$(lspci -nns ${d##*/})"
done
donePart5IOMMU編程接口
5.1內(nèi)核IOMMU API
#include <linux/iommu.h>
// 分配 IOMMU 域
struct iommu_domain *domain = iommu_domain_alloc(&pci_bus_type);
// 附加設備到域
iommu_attach_device(domain, &pdev->dev);
// 建立映射
iommu_map(domain, iova, paddr, size, IOMMU_READ | IOMMU_WRITE);
// 取消映射
iommu_unmap(domain, iova, size);
// 分離設備
iommu_detach_device(domain, &pdev->dev);5.2用戶空間VFIO API
#include <linux/vfio.h>
// 打開 VFIO 容器
int container = open("/dev/vfio/vfio", O_RDWR);
// 打開 IOMMU 組
int group = open("/dev/vfio/1", O_RDWR);
// 設置 IOMMU 類型
ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
// DMA 映射
struct vfio_iommu_type1_dma_map dma_map = {
.argsz = sizeof(dma_map),
.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
.vaddr = (uintptr_t)buffer,
.iova = device_address,
.size = buffer_size,
};
ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map);Part6IOMMU硬核攔截原理剖析
6.1地址翻譯:識破 “偽裝”
當 DMA 發(fā)起訪問請求時,IOMMU 首先會對請求中的 I/O 虛擬地址(IOVA)進行地址翻譯 。IOMMU 中維護著類似于 CPU 頁表的 IO 頁表,通過查詢 IO 頁表,IOMMU 可以將 IOVA 準確地轉換為物理地址(PA) 。這個過程就像是在一本詳細的地址翻譯詞典中查找對應的翻譯,詞典(IO 頁表)里記錄著 IOVA 和 PA 的對應關系,IOMMU 根據(jù)這個關系完成翻譯工作。
假設一個設備的DMA請求中包含的 IOVA 是 0x1000,IOMMU 通過查詢 IO 頁表,發(fā)現(xiàn)這個 IOVA 對應的 PA 是 0x20000,那么 IOMMU 就會將這個正確的物理地址傳遞給內(nèi)存訪問操作。通過這種地址翻譯機制,IOMMU 能夠清晰地識別 DMA 請求的真實目標。如果 DMA 請求的 IOVA 存在異常,比如指向了一個不存在的或非法的地址映射,IOMMU 就能立刻察覺,從而防止 DMA 訪問非法內(nèi)存地址 。這就好比一個人拿著錯誤的地圖導航(非法的 IOVA),而 IOMMU 作為專業(yè)的導航修正員,能夠發(fā)現(xiàn)錯誤并阻止其前往錯誤的目的地(非法內(nèi)存區(qū)域)。
6.2訪問控制:嚴守 “關卡”
在完成地址翻譯后,IOMMU 并不會立刻放行 DMA 請求,而是會對設備對目標內(nèi)存的訪問權限進行嚴格檢查 。IOMMU 中存儲著每個設備的訪問權限信息,這些信息規(guī)定了設備可以訪問的內(nèi)存區(qū)域以及訪問的類型(讀、寫、執(zhí)行等) 。就像每個員工都有自己的門禁權限,只能進入被授權的辦公室區(qū)域,設備也只能訪問被授予權限的內(nèi)存區(qū)域。
例如,一個網(wǎng)絡設備被授權只能讀取內(nèi)存中特定的網(wǎng)絡數(shù)據(jù)緩沖區(qū),當它發(fā)起 DMA 請求想要寫入其他內(nèi)存區(qū)域時,IOMMU 會迅速檢查到這種越權行為,立即阻止該 DMA 請求的執(zhí)行,并向系統(tǒng)報告錯誤 。通過這樣的權限檢查,IOMMU 就像是一個忠誠的衛(wèi)士,嚴守著內(nèi)存的 “關卡”,有效地阻止了 DMA 對未經(jīng)授權內(nèi)存區(qū)域的讀寫操作,實現(xiàn)了對系統(tǒng)內(nèi)存的嚴密保護,確保了系統(tǒng)內(nèi)存中數(shù)據(jù)的安全性和完整性。
6.3多級頁表與緩存機制:高效運作的秘訣
為了提高地址翻譯的效率和靈活性,IOMMU采用了多級頁表結構 。以常見的三級頁表為例,虛擬地址會被劃分為多個部分,每個部分對應不同級別的頁表索引 。當IOMMU接收到一個 IOVA 時,它首先會根據(jù)虛擬地址的最高位部分作為索引,在一級頁表(頁全局目錄)中查找對應的頁目錄項(PDE) 。
這個 PDE 指向二級頁表(頁目錄表),IOMMU再根據(jù)虛擬地址的次高位部分在二級頁表中查找對應的頁表項(PTE) ,最終通過PTE找到對應的物理頁框,完成地址翻譯 。這種多級頁表結構就像一個層層分類的大型圖書館索引系統(tǒng),每一級頁表都是一個分類索引,通過逐級查找,能夠快速定位到所需的物理地址,大大提高了地址翻譯的效率,同時也使得內(nèi)存的管理更加靈活,可以支持更大的地址空間。
為了進一步加速地址翻譯過程,IOMMU 還引入了 IOTLB(I/O Translation Lookaside Buffer) ,即 I/O 轉譯后備緩沖器,它相當于 IO 頁表的高速緩存 。IOTLB 中緩存了最近使用的 IOVA 到 PA 的地址轉換信息 。當 IOMMU 接收到 DMA 請求時,它會首先在 IOTLB 中查找是否有對應的地址轉換信息 。如果 IOTLB 命中,即找到了緩存的轉換信息,IOMMU 可以直接使用這些信息快速完成地址翻譯,而無需再去查詢多級頁表,大大節(jié)省了時間 。
只有當 IOTLB 未命中時,IOMMU 才會去查詢多級頁表進行地址翻譯 。這就好比你經(jīng)常使用的常用物品放在一個隨手可及的小抽屜(IOTLB)里,當你需要時可以快速拿到,而不需要去大型倉庫(多級頁表)中慢慢尋找,大大提高了效率。通過多級頁表和 IOTLB 的協(xié)同工作,在面對大量 DMA 請求時,IOMMU 仍能快速、準確地進行攔截操作,保障系統(tǒng)的穩(wěn)定運行。
























