摘要

本技術報告深入分析 CVE-2024-50264 ,一個存在於 Linux Kernel AF_VSOCK 子系統的嚴重 race condition 漏洞。該漏洞允許 use-after-free (UAF) 攻擊,導致權限提升。本分析報告探討此漏洞的技術基礎、攻擊限制以及潛在的緩解策略,並僅專注於技術層面。

深度解析 CVE-2024-50264:Linux Kernel 中長達八年的 Race Condition 漏洞剖析 | 資訊安全新聞

1 簡介

Kernel 子系統中的 Race Condition 屬於一類重大的漏洞,由於其時序限制與不穩定性,使其特別難以攻擊。在 Linux Kernel AF_VSOCK 子系統中發現的 CVE-2024-50264 就是其中一個,在2025年的一場主要資安會議上,它被認為是一個特別複雜的攻擊手法 [1]

AF_VSOCK 子系統為虛擬機器與其 hosts 之間提供 socket 式的通訊。此漏洞存在於 connect() 系統呼叫和 POSIX 訊號處理之間的 race condition,導致 use-after-free 寫入原語 (primitive)。值得注意的是,此漏洞 不需使用者命名空間 (namespaces) 即可觸發,這使其在受限的環境中更具危險性。

本報告探討 CVE-2024-50264 的技術細節、攻擊挑戰,以及研究人員為實現穩定攻擊所開發的創新方法。

2 漏洞分析

2.1 根本原因與簡介

此漏洞在2016年8月隨 Linux Kernel 4.8 版的 commit 06a8fc78367d 引入。它長達約八年未被發現,直到透過針對 AF_VSOCK 子系統的客製化模糊測試技術才被識別出來 [1]

核心問題源於 VSOCK socket 上的 connect() 系統呼叫與 POSIX 訊號傳遞之間的 race condition 。當成功攻擊時,此 race condition 會導致 use-after-free 條件,使得 Kernel 對一個已釋放的 virtio_vsock_sock 物件進行操作。

2.2 技術機制

當一個訊號在有漏洞的 socket 處於 TCP_ESTABLISHED 狀態時中斷了 connect() 系統呼叫,漏洞就會顯現。此訊號中斷導致 socket 轉換到 TCP_CLOSING 狀態:

  1. if (signal_pending(current)) {
  2. err = sock_intr_errno(timeout);
  3. sk->sk_state = sk->sk_state == TCP_ESTABLISHED ? TCP_CLOSING : TCP_CLOSE;
  4. sock->state = SS_UNCONNECTED;
  5. vsock_transport_cancel_pkt(vsk);
  6. vsock_remove_connected(vsk);
  7. goto out_wait;
  8. }

隨後,使用不同的 svm_cid (特別是 VMADDR_CID_HYPERVISOR ) 對同一個伺服器 VSOCK 進行第二次連線,會觸發記憶體損毀。

這個 connect() 呼叫執行 vsock_assign_transport() ,它將虛擬 socket 切換到新的傳輸機制並釋放與先前 VSOCK 傳輸機制相關的資源:

  1. if (vsk->transport) {
  2. if (vsk->transport == new_transport)
  3. return 0;
  4. vsk->transport->release(vsk);
  5. vsock_deassign_transport(vsk);
  6. }

由於錯誤的 TCP_CLOSING 狀態, virtio_transport_close() 會啟動進一步的通訊,排程一個 Kernel worker ( kworker ),該 worker 最終呼叫 virtio_transport_space_update() 。此函數對已釋放的結構進行操作:

  1. static bool virtio_transport_space_update(struct sock *sk, struct sk_buff *skb)
  2. {
  3. struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
  4. struct vsock_sock *vsk = vsock_sk(sk);
  5. struct virtio_vsock_sock *vvs = vsk->trans; /* UAF: ptr to freed object */
  6. bool space_available;
  7. if (!vvs)
  8. return true;
  9. spin_lock_bh(&vvs->tx_lock); /* UAF: requires 4 zero bytes */
  10. vvs->peer_buf_alloc = le32_to_cpu(hdr->buf_alloc); /* UAF write 4 bytes */
  11. vvs->peer_fwd_cnt = le32_to_cpu(hdr->fwd_cnt); /* UAF write 4 bytes */
  12. space_available = virtio_transport_has_space(vsk); /* UAF read */
  13. spin_unlock_bh(&vvs->tx_lock); /* UAF write: restores 4 zero bytes */
  14. return space_available;
  15. }
graph LR A[Create
listening
VSOCK
server] --> B[Client
connect
attempt]; B --> C[Signal
interrupts
connect]; C --> D[Socket state:
TCP_CLOSING]; D --> E[Second
connect
with
different CID]; E --> F[Transport
switch
frees
virtio_vsock_sock]; F --> G[Kworker
schedules]; G --> H[UAF
write on
freed
object];

2.3 有漏洞物件的記憶體佈局

virtio_vsock_sock 物件大小為80位元組,從 kmalloc-96 slab 快取中分配。記憶體損毀是由 Kernel worker 執行的 UAF 寫入。攻擊涉及的關鍵欄位包括:

  • tx_lock (4個位元組): 在嘗試取得自旋鎖 (spinlock) 時,必須包含零,否則 Kernel 會當掉。
  • peer_buf_alloc (4個位元組): 可控制的4位元組寫入原語 (primitive)。
  • peer_fwd_cnt (4個位元組): 可控制的4位元組寫入原語 (primitive)。

寫入 virtio_vsock_sock.peer_buf_alloc 的值可以透過 socket 選項從使用者空間控制:

  1. uaf_val_limit = 0x1lu; /* Cannot be zero */
  2. setsockopt(vsock1, PF_VSOCK, SO_VM_SOCKETS_BUFFER_MIN_SIZE,
  3. &uaf_val_limit, sizeof(uaf_val_limit));
  4. uaf_val_limit = 0xfffffffflu;
  5. setsockopt(vsock1, PF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
  6. &uaf_val_limit, sizeof(uaf_val_limit));
  7. /* Set the 4-byte value for UAF write */
  8. setsockopt(vsock1, PF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
  9. &uaf_val, sizeof(uaf_val));

3 攻擊挑戰與技術

3.1 攻擊限制

CVE-2024-50264 為攻擊開發者帶來了幾項重大挑戰,被研究人員描述為「the worst bug to exploit I've ever seen 」(我見過最難利用的 bug) [1] :

  1. 分配限制 : 有漏洞的 virtio_vsock_sock 用戶端物件與伺服器物件從同一個 slab 快取中分配,這為記憶體操作帶來困難。
  2. 時序敏感性 : race condition 需要 connect() 呼叫與訊號傳遞之間的精確時序,這使得穩定攻擊具有挑戰性。
  3. 狀態管理 : socket 必須在攻擊過程中的精確時刻處於特定狀態 (先是 TCP_ESTABLISHED ,接著是 TCP_CLOSING )。
  4. 記憶體損毀限制 : UAF 寫入原語 (primitive) 僅限於已釋放物件內的特定欄位,這限制了可能的記憶體修改類型。

3.2 訊號傳遞技術

研究人員沒有使用傳統訊號 (如 SIGKILL ,會終止攻擊程序),而是發現一種創新的方法,使用訊號33,該訊號由 Native POSIX Threads Library (NPTL) 保留用於內部操作:

  1. struct sigevent sev = {};
  2. timer_t race_timer = 0;
  3. sev.sigev_notify = SIGEV_SIGNAL;
  4. sev.sigev_signo = 33; /* NPTL internal signal */
  5. ret = timer_create(CLOCK_MONOTONIC, &sev, &race_timer);

此訊號非常適合攻擊,因為:

  • 可以使用 timer_settime() 精確計時
  • 對攻擊程序來說是隱形的
  • 傳遞後不會終止攻擊程序
sequenceDiagram participant E as Exploit Process participant K as Kernel participant W as Kworker E->>K: connect() on VSOCK Note over E,K: Race condition window E->>K: Signal 33 delivery K->>K: Interrupt connect(), set TCP_CLOSING E->>K: Second connect() with different CID K->>K: Free virtio_vsock_sock object K->>W: Schedule kworker W->>W: UAF write on freed object

程式碼範例

以下程式碼範例說明了漏洞攻擊的關鍵層面:

為 Race Condition 設定訊號

  1. /* Setup signal 33 for interrupting connect() */
  2. struct sigevent sev = {};
  3. timer_t race_timer = 0;
  4. sev.sigev_notify = SIGEV_SIGNAL;
  5. sev.sigev_signo = 33; /* NPTL internal signal */
  6. ret = timer_create(CLOCK_MONOTONIC, &sev, &race_timer);

用於 UAF 控制的 Socket 選項操作

  1. /* Configure the value to be written during UAF */
  2. uaf_val_limit = 0x1lu; /* Minimum value (cannot be zero) */
  3. setsockopt(vsock1, PF_VSOCK, SO_VM_SOCKETS_BUFFER_MIN_SIZE,
  4. &uaf_val_limit, sizeof(uaf_val_limit));
  5. uaf_val_limit = 0xfffffffflu; /* Maximum value */
  6. setsockopt(vsock1, PF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
  7. &uaf_val_limit, sizeof(uaf_val_limit));
  8. /* Set specific value for UAF write */
  9. setsockopt(vsock1, PF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
  10. &uaf_val, sizeof(uaf_val));

3.3 攻擊策略

攻擊策略涉及幾個精確步驟:

  1. 設定 : 建立一個監聽的 VSOCK 伺服器 socket
  2. 觸發 Race Condition : 啟動連線嘗試,並以精確計時的訊號33中斷它
  3. 觸發 UAF : 使用不同的 CID 進行第二次連線嘗試以釋放目標物件
  4. 記憶體操作 : 使用 UAF 寫入原語 (primitive) 修改 Kernel 記憶體結構
  5. 權限提升 : 利用記憶體修改來獲得更高的權限

UAF 寫入原語 (primitive) 允許修改已釋放物件內特定偏移處的四位元組值,這可以用來劫持 (hijack) Kernel 控制流程或修改關鍵的安全變數。

4 緩解策略

4.1 修補與漏洞管理

根據漏洞管理最佳實踐,像 CVE-2024-50264 這樣的漏洞主要緩解措施是及時修補。Google 的漏洞分類系統根據其嚴重性與攻擊潛力對此類漏洞進行分類 [2,3] :

嚴重程度等級 描述
關鍵 (Critical) 存在於所有叢集 (cluster),且未經認證的遠端攻擊者可輕易利用並導致完整系統受損的漏洞
高 (High) 存在於許多叢集 (cluster),且攻擊者可利用並導致機密性、完整性或可用性喪失的漏洞
中 (Medium) 存在於部分叢集 (cluster),但因Configuration、攻擊難度、所需存取權限或使用者互動而使機密性、完整性或可用性喪失程度有限的漏洞
低 (Low) 所有其他攻擊可能性極低且後果有限的漏洞

4.2 技術緩解

有幾種技術方法可以緩解此類漏洞:

  1. Use-After-Free 偵測器 : 增強的記憶體除錯器 (debugger) 工具,如 KASAN,有助於在開發與測試期間識別 UAF 條件。
  2. 引用計數 (Reference Counting) : 改善 Kernel 物件的引用計數機制,可防止過早釋放。
  3. 鎖定策略 : 在網路子系統的狀態轉換周圍使用更好的鎖定機制,可防止 race condition。
  4. 靜態分析 : 先進的靜態分析工具可以在程式碼審查程序中識別潛在的 race condition。

5 結論

CVE-2024-50264 代表了 Linux Kernel 中一類複雜的漏洞,需要深入的技術理解和創新的方法才能成功攻擊。它的發現與攻擊證明了 Kernel 漏洞研究的不斷發展,特別是在識別和利用像 AF_VSOCK 這樣複雜子系統中的 race condition 方面。

與攻擊此漏洞相關的技術挑戰—包括時序精確度、訊號處理的複雜性以及記憶體操作限制—突顯了成功攻擊所需的高級技能。同時,此漏洞在被發現前存在近八年的事實,強調了透過傳統測試方法識別此類 race condition 的困難。

從防禦角度來看,CVE-2024-50264 強調了全面模糊測試、先進靜態分析工具和及時修補程序的重要性。隨著 Kernel 安全的不斷演進,此類複雜的漏洞可能會持續成為高階攻擊者的重要目標,並為防禦者帶來挑戰。