1. 簡介
Linux Kernel 的網路子系統,特別是流量控制(Traffic Control, TC)框架,在管理網路封包流動方面扮演關鍵角色。在此框架中,使用了多種佇列規則(qdiscs)來調度(Schedule)、整形(Shape)和排列(Prioritize)網路流量。其中一種 qdisc 是 CAKE (Common Applications Kept Enhanced),目的在提供進階的擁塞控制和公平性。這份分析深入探討 Linux Kernel
net/sched
CAKE qdisc 中發現的一個關鍵 Use-After-Free (UAF) 漏洞,該漏洞可能導致本機權限提升 (LPE)
[1]
。我們將探討此缺陷的技術細節、根本原因、觸發機制,以及潛在的攻擊向量,並參考一般的 Kernel 攻擊技術(例如 heap shaping)。
2. 技術背景:Qdisc 與流量控制
Linux Kernel 的流量控制系統使用 qdiscs 來管理封包佇列。Qdiscs 大致可分為 classless 和 classful。Classless qdiscs 執行簡單的佇列操作,而 classful qdiscs 則允許階層化組織以及對流量進行更細緻的控制。Hierarchical Fair Service Curve (HFSC) qdisc 是一個 classful qdisc 的例子,提供複雜的頻寬分配和延遲保證。另一方面,CAKE 是一個更現代的 qdisc,將 AQM (Active Queue Management)、流量整形和流量隔離(Flow isolation)等多項功能整合到單一且易於使用的機制中。瞭解這些 qdiscs 與 Kernel 記憶體管理之間的互動,對於理解 UAF 漏洞至關重要。Kernel 記憶體分配器(例如 page allocator (buddy allocator) 和 slab allocators (SLUB, SLAB, SLOB))是 Kernel 中分配與釋放物件的基礎 [2] 。在 Kernel 漏洞中,經常利用 heap shaping 等技術,透過操縱 Kernel 堆積佈局來放置特定物件以進行利用 [2] 。
3. 根本原因分析
CAKE qdisc UAF 漏洞的核心在於
cake_enqueue
函式中不一致的傳回值。具體來說,即使
cake_enqueue
因為緩衝區限制而捨棄封包,它仍可能傳回
NET_XMIT_SUCCESS
。當 CAKE 被用作像 HFSC 這樣的 classful 父 qdisc 下的子 qdisc 時,這種行為會產生關鍵的去同步化。
請參考以下來自
cake_enqueue
的簡化程式碼片段
[1]
:
- static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
- struct sk_buff **to_free)
- {
- // ... other code ...
- if (q->buffer_used > q->buffer_limit) { // [1]
- u32 dropped = 0;
- while (q->buffer_used > q->buffer_limit) {
- dropped++;
- cake_drop(sch, to_free); // [2]
- }
- b->drop_overlimit += dropped;
- }
- return NET_XMIT_SUCCESS;
- }
如程式碼所示,如果
q->buffer_used
超過
q->buffer_limit
,封包會經由
cake_drop
被捨棄
[1]
。然而,該函式無條件傳回
NET_XMIT_SUCCESS
。這意味著父 qdisc(例如 HFSC)會認為封包已成功進入佇列,即使它已被 CAKE 捨棄。這種差異是 UAF 狀態的初始觸發點。
4. 漏洞觸發機制
當 HFSC qdisc 配置在 CAKE qdisc 之上時,就會顯現 UAF 漏洞。導致 UAF 的事件序列如下:
- HFSC qdisc 將一個包排入(enqueue)其子 CAKE qdisc 的佇列。
-
CAKE qdisc 的
cake_enqueue函式因緩衝區限制而捨棄封包,但傳回NET_XMIT_SUCCESS[1] 。 -
HFSC qdisc 在不知道封包已被捨棄的情況下,繼續執行,彷彿入隊(enqueue)成功。如果這是特定 HFSC 類別的第一個封包,則會呼叫
init_ed函式,將該類別加入 HFSC 的 active list [1] 。 -
隨後,該 HFSC qdisc 類別被移除,這會呼叫
hfsc_delete_class。此函式轉而呼叫qdisc_purge_queue來清除子 CAKE qdisc [1] 。 -
qdisc_purge_queue呼叫qdisc_tree_reduce_backlog。此時,由於 CAKE qdisc 是空的(因為封包已被捨棄),qlen和backlog為 0 [1] 。 -
關鍵問題出現在
qdisc_tree_reduce_backlog。因為qlen為 0,該函式的邏輯阻止了qlen_notify被呼叫 [1] 。這意味著 HFSC qdisc 的父類別沒有從其 active list 中移除,從而留下一個指向已釋放 HFSC 類別結構的 dangling pointer。
下圖說明了 qdisc 階層以及 dangling pointer 的產生:
5. 攻擊分析
HFSC active list 中指向已釋放 HFSC 類別的 dangling pointer 可被用於攻擊利用。當隨後呼叫
hfsc_dequeue
時,它會嘗試使用此 dangling pointer 來存取已釋放的 HFSC 類別
[1]
。這種 UAF 狀態允許攻擊者操縱已釋放的記憶體區域。利用過程通常涉及:
- Heap Shaping: 在 UAF 發生之前,攻擊者可以使用 heap shaping 技術來控制記憶體佈局。這包括分配和釋放特定大小的 Kernel 物件,以確保當 HFSC 類別被釋放時,它原先佔用的記憶體可以被攻擊者控制的資料重新分配 [2] 。例如,透過瞭解 Kernel 的 slab allocator 行為,攻擊者可以分配將會佔用已釋放 HFSC 類別記憶體的物件。這讓攻擊者能控制已釋放記憶體的內容,有效地將 UAF 轉換為受控的讀取/寫入基本功能(primitive)。hoeasys.com 上關於 ksmbd CVE-2025-37947 的文章提供了 Kernel 利用中 heap shaping 的絕佳概覽,詳細說明了攻擊者如何操縱記憶體分配器(page allocator 和 slab allocators)來放置特定物件以進行利用 [2] 。這涉及預先分配和控制堆積記憶體,以確保越界寫入(out-of-bounds writes)可以精確地損毀或操縱關鍵資料結構,或是透過耗盡特定的 free lists 來強迫分配器將目標物件放置在所需的位置 [2] 。
-
RIP 控制:
當在
hfsc_dequeue內存取已被釋放的cl->qdisc時,會發生 UAF。原始文章強調qdisc_dequeue_peeked藉由引用已釋放的sch來呼叫sch->dequeue[1] 。藉由控制已釋放Qdisc結構的內容(透過 heap shaping),攻擊者可以用任意位址覆蓋dequeue函式指標。當sch->dequeue(sch)被呼叫時,它將執行攻擊者控制的程式碼,導致在 Kernel 空間執行任意程式碼,並最終實現本機權限提升。
以下來自
qdisc_dequeue_peeked
的程式碼片段說明了 RIP 控制點
[1]
:
- static inline struct sk_buff *qdisc_dequeue_peeked(struct Qdisc *sch)
- {
- struct sk_buff *skb = skb_peek(&sch->gso_skb);
- if (skb) {
- // ... other code ...
- } else {
- skb = sch->dequeue(sch); // [1]
- }
- return skb;
- }
在此程式碼中,如果
sch->gso_skb
為空,執行路徑會導致呼叫
sch->dequeue(sch)
。如果
sch
指向一個已被攻擊者重新控制的已釋放記憶體區域,攻擊者就可以覆蓋
Qdisc
結構內的
dequeue
函式指標。這允許攻擊者將執行流重新導向到任意位址,從而完全控制 Kernel 的執行環境。
6. 緩解與結論
Linux Kernel
net/sched
CAKE qdisc 中的漏洞凸顯了在複雜 Kernel 子系統中一致性狀態管理和錯誤處理的至關重要性。根本原因(來自
cake_enqueue
不一致的傳回值)展示了看似微小的邏輯缺陷在與 qdiscs 的階層性質結合時,如何演變成嚴重的 UAF 漏洞。為了緩解此類問題,Kernel 開發人員必須確保所有函式都能準確反映其運作結果,特別是在處理資源分配和釋放時。
一個潛在的修復方法涉及修改
cake_enqueue
,使其在封包因緩衝區限制而被捨棄時傳回錯誤代碼(例如
NET_XMIT_DROP
),而非
NET_XMIT_SUCCESS
。這將允許父 qdiscs(例如 HFSC)正確處理捨棄的封包,並防止 dangling pointer 的產生。此外,對已釋放物件進行更強健的檢查,以及在 dereferencing 指標前進行更嚴格的驗證,都有助於防止 UAF 狀態被利用。
總之,CAKE qdisc UAF 漏洞提醒我們,在確保複雜作業系統 Kernel 安全方面面臨著持續挑戰。它強調了細緻的程式碼審查、全面的測試以及對組件間互動深入理解的需求,以防止並識別可能具有重大安全影響的微小缺陷。對此類漏洞的利用通常依賴於像 heap shaping 這樣複雜的技術,這強調了 Kernel 內需要強健的記憶體管理和保護機制。