AArch64 Linux 中的指標認證¶
作者:Mark Rutland <mark.rutland@arm.com>
日期:2017-07-19
本文件簡要描述了 AArch64 Linux 中指標認證功能的提供。
架構概述¶
ARMv8.3 指標認證擴充套件添加了可用於緩解某些類攻擊的原語,在這些攻擊中,攻擊者可以破壞某些記憶體的內容(例如,堆疊)。
該擴充套件使用指標認證程式碼 (PAC) 來確定指標是否已被意外修改。 PAC 從指標、另一個值(例如堆疊指標)以及儲存在系統暫存器中的金鑰派生。
該擴充套件添加了將有效 PAC 插入指標以及驗證/從指標中刪除 PAC 的指令。 PAC 佔據指標的若干高位,具體取決於配置的虛擬地址大小以及是否使用指標標記。
這些指令的一個子集已從 HINT 編碼空間分配。 在沒有擴充套件的情況下(或停用時),這些指令的行為類似於 NOP。 使用這些指令的應用程式和庫可以正確執行,而與擴充套件的存在無關。
該擴充套件提供了五個獨立的金鑰來生成 PAC - 兩個用於指令地址 (APIAKey, APIBKey),兩個用於資料地址 (APDAKey, APDBKey),一個用於通用身份驗證 (APGAKey)。
基本支援¶
選擇 CONFIG_ARM64_PTR_AUTH 並且存在相關的 HW 支援時,核心將在 exec*() 時為每個程序分配隨機金鑰值。 這些金鑰由程序中的所有執行緒共享,並在 fork() 中保留。
地址認證功能的存在透過 HWCAP_PACA 宣告,通用認證功能透過 HWCAP_PACG 宣告。
PAC 在指標中佔據的位數是 55 減去核心配置的虛擬地址大小。 例如,如果虛擬地址大小為 48,則 PAC 的寬度為 7 位。
選擇 ARM64_PTR_AUTH_KERNEL 時,核心將使用 HINT 空間指標認證指令編譯,以保護函式返回。 使用此選項構建的核心可在具有或不具有指標認證支援的硬體上執行。
除了 exec() 之外,還可以使用 PR_PAC_RESET_KEYS prctl 將金鑰重新初始化為隨機值。 PR_PAC_APIAKEY、PR_PAC_APIBKEY、PR_PAC_APDAKEY、PR_PAC_APDBKEY 和 PR_PAC_APGAKEY 的位掩碼指定要重新初始化哪些金鑰; 指定 0 表示“所有金鑰”。
除錯¶
選擇 CONFIG_ARM64_PTR_AUTH 並且存在對地址認證的 HW 支援時,核心將在 NT_ARM_PAC_MASK regset(結構 user_pac_mask)中公開 TTBR0 PAC 位的的位置,使用者空間可以透過 PTRACE_GETREGSET 獲取該位置。
僅當設定了 HWCAP_PACA 時,才公開 regset。 為資料指標和指令指標公開單獨的掩碼,因為兩組 PAC 位可能有所不同。 請注意,這些掩碼適用於 TTBR0 地址,並且不適用於 TTBR1 地址(例如,核心指標)。
此外,如果還設定了 CONFIG_CHECKPOINT_RESTORE,核心將公開 NT_ARM_PACA_KEYS 和 NT_ARM_PACG_KEYS regset(結構 user_pac_address_keys 和結構 user_pac_generic_keys)。 這些可用於獲取和設定執行緒的金鑰。
虛擬化¶
當透過傳遞標誌 KVM_ARM_VCPU_PTRAUTH_[ADDRESS/GENERIC] 並在初始化每個虛擬 CPU 時請求啟用這兩個單獨的 CPU 功能時,將在 KVM 客戶機中啟用指標認證。 當前的 KVM 客戶機實現透過同時啟用這兩個功能來工作,因此在啟用指標認證之前會檢查這兩個使用者空間標誌。 如果將來新增對獨立啟用這兩個功能的支援,則單獨的使用者空間標誌將允許不進行使用者空間 ABI 更改。
由於 Arm 體系結構指定指標認證功能與 VHE 功能一起實現,因此 KVM arm64 ptrauth 程式碼依賴於 VHE 模式的存在。
此外,如果未設定這些 vcpu 功能標誌,則 KVM 將從 KVM_GET/SET_REG_* ioctl 中過濾掉指標認證系統金鑰暫存器,並從 cpufeature ID 暫存器中遮蔽這些功能。 任何使用指標認證指令的嘗試都將導致將 UNDEFINED 異常注入到客戶機中。
啟用和停用金鑰¶
prctl PR_PAC_SET_ENABLED_KEYS 允許使用者程式控制在特定任務中啟用哪些 PAC 金鑰。 它接受兩個引數,第一個引數是 PR_PAC_APIAKEY、PR_PAC_APIBKEY、PR_PAC_APDAKEY 和 PR_PAC_APDBKEY 的位掩碼,指定此 prctl 應影響哪些金鑰,第二個引數是相同位的位掩碼,指定是否應啟用或停用金鑰。 例如
prctl(PR_PAC_SET_ENABLED_KEYS,
PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY,
PR_PAC_APIBKEY, 0, 0);
停用除 IB 金鑰之外的所有金鑰。
這有用的主要原因是啟用使用 PAC 指令簽名和驗證函式指標以及函式外部暴露的其他指標的使用者空間 ABI,同時仍然允許符合 ABI 的二進位制檔案與不簽名或驗證指標的舊二進位制檔案互操作。
其思路是,動態載入器或早期啟動程式碼會在確定程序可能載入舊二進位制檔案之後,但在執行任何 PAC 指令之前,很早地發出此 prctl。
為了與之前的核心版本相容,程序在啟動時啟用了 IA、IB、DA 和 DB,並在 exec() 時重置為此狀態。 透過 fork() 和 clone() 建立的程序從呼叫程序繼承金鑰啟用狀態。
建議避免停用 IA 金鑰,因為停用此金鑰比停用任何其他金鑰具有更高的效能開銷。