摘要

此報告分析 CVE-2026-23111,這是 Linux 核心 nftables 子系統中一個關鍵的釋放後使用(use-after-free, UAF)漏洞。該缺陷源於 transaction rollback 過程中 nft_map_catchall_activate 的邏輯錯誤。我們檢視 nftables 架構、generation mask 以及導致記憶體損毀的序列。透過分析 netfilter hooks 與 transaction management 之間的互動,我們展示無特權使用者如何經由確定性的堆積操作來提升權限。與 CVE-2024-50264 [2] 的比較,突顯了保護核心 State machine 的挑戰。

nftables 的 catchall 元素真的是 UAF 元兇嗎?Netfilter rollback 邏輯的驚人缺陷! | 資訊安全新聞

1. 簡介

Linux 網路堆疊使用 netfilter 進行封包過濾與 NAT。Nftables 作為 iptables 的後繼者,透過 transactional API [1] 提供了靈活的規則集管理基礎設施。在 concurrent transactions 之間管理物件生命週期既複雜又容易出錯。CVE-2026-23111 是一個在失敗操作復原期間核心一致性受到破壞的漏洞。它利用了集合中 "catchall" 元素的邏輯缺陷,導致參考計數器不匹配,進而造成物件過早釋放。

2. nftables 架構框架

要理解此漏洞,必須先了解 nftables 的階層結構。在最上層, nft_table 容器容納了各種物件,包括 chains、sets 和 rules。Chains( struct nft_chain )會掛載到特定的 netfilter hooks,例如 ingress post-routing ,並在此處攔截和處理封包。這些 chains 中的 rules( struct nft_rule )包含 expressions( struct nft_expr ),這些 expressions 會根據 packet metadata 執行動作。

此架構中的關鍵組件是 set 基礎設施( struct nft_set )。Sets 允許對 IP 位址、連接埠或其他選擇器進行高效能查詢。某些 sets,稱為 verdict maps,會將鍵值對應到特定的 verdicts,如 NFT_JUMP NFT_GOTO ,這些 verdicts 會參照其他 chains。"catchall" 元素則在沒有其他 set 元素符合查詢時,作為預設動作。此架構確保了在核心層級執行安全邊界,正如當代關於作業系統層級網路強制執行的研究所指出 [3]

sequenceDiagram participant User as Userspace (Netlink) participant Kernel as Kernel (nftables) participant Mem as Memory (Slab/Heap) User->>Kernel: Send Batch Transaction (Delete Map + Invalid Cmd) Note over Kernel: Start Processing Transaction 1 Kernel->>Kernel: Deactivate Catchall Element Kernel->>Mem: Decrement Chain Refcount (Ref -> 0) Note over Kernel: Start Processing Transaction 2 Kernel->>Kernel: Encounter Error (Invalid Command) Kernel->>Kernel: Trigger Abort Process Note over Kernel: Rollback Transaction 1 Kernel->>Kernel: Call nft_map_catchall_activate() Note right of Kernel: BUG: Skips deactivated element Kernel-->>User: Return Error (Catchall stays inactive, Refcount stays 0) User->>Kernel: Request Delete Chain Kernel->>Mem: Free Chain Memory Note over Kernel,Mem: UAF: Other objects still point to freed Chain

3. 漏洞深入探討:CVE-2026-23111

3.1 Transaction Management 與 Generation Masks

Nftables 利用 Generation 機制來確保 Atomic update。每個物件都有一個 2 位元的位元遮罩 (genmask)。 gencursor 定義了「當前」與「下一個」Generation。當物件被新增時,它在當前 Generation 被標記為 inactive,但在下一個 Generation 為 active 。在成功 commit 後,cursor flip。相反地,在刪除期間,物件在下一個 Generation 會被標記為 inactive。如果 Transaction 失敗,核心必須復原這些變更,以還原「當前」狀態。

3.2 Catchall 元素機制

Catchall 元素的處理方式與標準 set 元素不同。標準元素儲存在如 hash tables 或 red-black tree 等後端結構中,而 catchall 元素則位於一個通用 list ( set->catchall_list ) 中。這個區別至關重要,因為 catchall 元素的啟用與停用邏輯是獨立於主要 set 邏輯實作的。

3.3 nft_map_catchall_activate() 的根本原因分析

此漏洞的核心在於復原機制的失敗。當一個刪除 set 的 Transaction 被中止時,核心會呼叫 nft_map_catchall_activate() 來重新啟用 catchall 元素。此函數的原始實作包含一個邏輯反轉:

  1. /*
  2. * Analysis of the vulnerable nft_map_catchall_activate function.
  3. * This function is responsible for reactivating catchall elements during an abort.
  4. */
  5. void nft_map_catchall_activate(const struct nft_ctx *ctx, struct nft_set *set)
  6. {
  7. struct nft_set_elem_catchall *catchall;
  8. // Iterate through the list of catchall elements in the set
  9. list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
  10. /*
  11. * BUG: The function checks if the element is ACTIVE in the next generation.
  12. * During an abort of a deletion, the element is currently INACTIVE in the next gen.
  13. * This check causes the function to skip the very elements it needs to reactivate.
  14. */
  15. if (!nft_set_elem_active(catchall->elem, nft_genmask_next(ctx->net)))
  16. continue;
  17. // This line is only reached for elements that are already active, which is redundant.
  18. nft_set_elem_activate(ctx->net, set, catchall->elem);
  19. }
  20. }

如程式碼分析所示,對於任何被標記為刪除(在下一個 Generation 為 inactive)的元素,都會觸發 continue 陳述式。結果,catchall 元素維持 inactive 狀態,且關聯的 chain 參考計數器永遠不會被恢復為原始值 [1]

4. 攻擊向量與記憶體損毀

4.1 觸發 Transaction Abort

攻擊者可以透過建構一個包含兩個 Transaction 的 Netlink 批次來觸發此條件。第一個 Transaction 刪除一個帶有指向目標 chain 之 catchall 元素的 verdict map。這個動作會遞減 chain 的參考計數器。第二個 Transaction 被設計為會失敗(例如,提供一個無效的屬性),強迫核心進入 abort 路徑。由於 nft_map_catchall_activate() 中的錯誤,即使 catchall 元素在理論上仍存在於「當前」Generation,chain 的參考計數器仍保持遞減狀態。

4.2 參考計數器不一致

如果 chain 的參考計數器降至零,核心會假設它不再被使用。攻擊者接著可以發出單獨的指令來刪除該 chain。然而,如果另一個 rule 或物件仍持有指向此 chain 的過時指標,就會發生釋放後使用(Use-After-Free, UAF)的狀況。當 Kernel 稍後嘗試使用該過時指標來處理封包時,它會存取已釋放的記憶體。

此類 UAF 攻擊原型的利用通常涉及「Heap grooming」或「Heap shaping」,攻擊者會用受控資料填充剛釋放的記憶體。此技術類似於 CVE-2024-50264 [2] 中所描述的,其中時序敏感的 Race Condition 被用來操縱 kmalloc 配置。在 CVE-2026-23111 的情況下,由於其依賴於 Transaction 邏輯而非 Race Condition,利用過程更具確定性。

5. 與相關核心漏洞的比較研究

nftables 中的漏洞與 AF_VSOCK UAF(CVE-2024-50264)在概念上有相似之處。兩個漏洞都涉及在複雜轉換過程中物件狀態的管理不當。然而,CVE-2024-50264 依賴於 connect() 與訊號處理 [2] 之間的 Race Condition,而 CVE-2026-23111 則是 State machine 本身的邏輯缺陷。

下表比較了這兩個漏洞:

功能 / 特性 CVE-2026-23111 (nftables) CVE-2024-50264 (AF_VSOCK)
子系統 Netfilter / nftables AF_VSOCK (虛擬 Socket)
觸發條件 Transaction Abort 邏輯 Race Condition (Signal vs Connect)
物件類型 struct nft_chain struct virtio_vsock_sock
確定性 高 (基於邏輯) 低 (時序敏感)
根本原因 反向的啟用檢查 訊號導致的錯誤狀態轉換

此類漏洞的持續存在顯示,即使具備 transactional update 等進階功能,手動管理參考計數器仍然是安全回歸的重要來源。隨著網路安全邊界為了避免 Parser 差異 [3] 而轉向核心層級強制執行,像 nftables 這樣的子系統的完整性變得至關重要。

6. 緩解策略

CVE-2026-23111 的主要緩解措施是套用官方 Kernel Patch 程式,該 Patch 程式修正了 nft_map_catchall_activate() 中的邏輯。此修復確保在中止期間,只有那些在下一 Generation 中「非」 Active 的元素(即剛剛被 Deactivated 元素)才會被作為重新啟用的目標。

從更廣泛的角度來看,防禦措施包括:

  • 核心位址除錯器 (Kernel Address Sanitizer, KASAN): 在測試期間使用 KASAN 以在發生時立即偵測 UAF 狀況。
  • Refcount 強化: 實作飽和參考計數器以防止溢位 / 下溢攻擊。
  • 降低權限: 在無特權的名稱空間中限制對 CAP_NET_ADMIN 的存取,這通常是與 nftables 互動所需的。

7. 結論

CVE-2026-23111 強調了核心狀態管理的複雜性。透過利用 nftables transaction rollback 中一個細微的邏輯錯誤,攻擊者可以繞過參考計數保護來達成釋放後使用(Use-After-Free, UAF)的狀況。此研究證明,即使是為原子性設計的穩健框架,如果其錯誤處理路徑未經嚴格驗證,也可能引入新的攻擊面。與 AF_VSOCK 子系統中先前漏洞的比較表明,UAF 仍然是核心安全中的主要威脅,這使得靜態分析和執行時期記憶體保護的持續創新變得至關重要。