資安雷達 2026 年 9 月 17 日

2026-09-17 — KVM/arm64 巢狀虛擬化型別截斷:主機分頁被寫壞

primary=https://www.openwall.com/lists/oss-security/2026/09/16/14

KVM/arm64 巢狀虛擬化型別截斷:主機分頁被寫壞

openwall oss-security · 2026-09-16

一個型別截斷錯誤,讓 KVM/arm64 巢狀虛擬化路徑裡「stage-1 位址轉換層級」的計算結果被誤判成 0,而這個 0 原本的意思是「大小未知」,卻被下游的失效(invalidation)邏輯當成合法答案接受。這個問題被列為 CVE-2026-89775,由 oss-security 於 2026-09-16 公開揭露,效果是讓已經釋放的 host 記憶體頁持續以可寫狀態留在固定位址,guest 可以直接讀寫而不觸發任何 VM exit。在 /dev/kvm 權限被設成 0666(world-writable)的發行版上,一般使用者只要能建立自己的虛擬機器,就能藉此取得 root 權限。

漏洞機制

要理解這個漏洞,得先知道 VNCR_EL2 是什麼。Armv8.4 巢狀虛擬化擴充 FEAT_NV2 讓跑在 EL2 的 L1 hypervisor,把原本得逐一 trap 模擬的虛擬 EL2 暫存器,改成直接存取記憶體中一個頁面(VNCR 頁),藉此避免每次存取都要離開硬體加速路徑、跳回 host 處理。KVM 因此得把這個 L1 VNCR 頁映射進 host 自己的 stage-1(host kernel 的頁表),套用對應的 guest stage-1 權限,並用一個稱為 pseudo-TLB 的快取記錄映射有效性,因為 guest 隨時可能改變底層實體頁或存取權限。

ARM 的位址轉換用「層級」(level)決定每一級分頁表涵蓋的位址範圍,層級值原本只需要極少的位元就能表示。程式在計算某個 stage-1 對映涵蓋的大小時,對這個層級值做了型別截斷,使某些合法層級被截斷成錯誤結果,讓算出來的「大小」變成 0。正常設計裡 0 應該代表「大小未知、不可拿來做任何假設」,但 VNCR pseudo-TLB 的失效邏輯卻直接把 0 當成有效答案接受。

失效範圍的算法是「起始位址到起始位址加大小」,大小是 0 時這個範圍就退化成一個空區間,起點等於終點。任何要清掉這個 pseudo-TLB 項目、把對映標記失效的呼叫都會被這個空區間擋下,實際上什麼都沒發生。於是當 host 因記憶體回收、頁面搬移或 guest stage-2 權限變動而釋放那個實體頁後,host kernel 裡對映到 VNCR 固定位址的那條 stage-1 entry 完全沒被清掉,繼續指向一塊已歸還給系統、隨時可能被挪作他用的記憶體。

VNCR 存取本來就是 FEAT_NV2 設計成不必離開硬體加速路徑的機制,guest 只要照常存取被重新導向的虛擬 EL2 暫存器,就等於直接對那塊已釋放、仍可寫的 host 實體頁做 64 位元讀寫,全程不觸發任何 trap 或 VM exit,host 端毫無察覺機會。攻擊者能靠這個原始讀寫能力,在 host kernel 記憶體裡偽造資料結構或竄改控制流,達成從 guest 到 host 的完整逃逸。

受影響版本

受影響範圍是 mainline 核心裡從 commit 7270cc9157f47(2025-05-14 併入,引進這段層級計算邏輯)到 8053393680d4(2026-08-06 修補提交)之間的所有版本。只有同時滿足兩個條件的系統才會真正暴露:一是核心啟用了 KVM/arm64 的巢狀虛擬化支援,也就是讓 L1 guest 能自己再跑 L2 guest 並用到 FEAT_NV2/VNCR 加速;二是 host 上確實有惡意或受控的 L1 guest 在執行。

一般的單層 KVM/arm64 虛擬化(host 只跑一般 guest、不開巢狀)不會踩進這條路徑,因為 VNCR 映射本來就只為了替 L1 hypervisor 加速虛擬 EL2 暫存器存取而存在。風險最集中的場景是提供巢狀虛擬化功能的多租戶 arm64 公有雲,租戶自帶 hypervisor 跑進一步的巢狀 guest,也就直接握有觸發這段錯誤路徑所需的存取能力。

修補與緩解

主線核心的修補提交 8053393680d4 重新處理層級到大小的換算邏輯,不再讓一個原本合法的層級值在計算過程中被截斷成 0。修補後的邏輯把「大小等於 0」與「大小未知」明確分開,一旦判斷不出確切大小,pseudo-TLB 就必須保守地執行失效,而不是把不確定結果當成範圍是空的、什麼都不用做。

階段修補前修補後
層級→大小計算層級值型別截斷,合法層級可能算出大小 0保留完整層級寬度,不再產生假的 0
大小為 0 時的判斷當成「有效、範圍是空的」直接放行視為「大小未知」,觸發保守處理
失效範圍起點等於終點,恆為空區間,失效呼叫必被跳過以已知合法範圍強制執行實際失效
結果已釋放頁面持續留在 host stage-1,仍可寫已釋放頁面的對映確實被清除

在還沒套用修補的系統上,最直接的緩解是先確認 host 是否真的需要巢狀虛擬化——多租戶或不信任 L1 guest 的環境應該先關掉這項功能,直到升級到含修補的核心。同樣重要的是檢查 /dev/kvm 的權限,只要維持預設的 0660 且僅屬於 kvm 群組,一般使用者就沒有建立虛擬機器的管道;一旦把它開成 0666 世界可寫,等於把一個 host kernel 記憶體漏洞直接變成任何本機使用者都能用的 root 提權工具。

原始來源:oss-security: CVE-2026-89775 Guest-to-Host Escape in KVM/arm64


End of article
0
Would love your thoughts, please comment.x
()
x