資安雷達 2026 年 9 月 27 日

2026-09-27 — CVE-2025-39964:AF_ALG 競爭寫入提權漏洞

primary=https://idnsec.com/research/linux-local-privilege-escalation-with-af-alg/ primary=https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=1b34cbbf4f011a121ef7b2d7d6e6920a036d5285

CVE-2025-39964:AF_ALG 競爭寫入提權漏洞

IDNSEC · 2026-09-25

兩個執行緒同時對同一個 AF_ALG socket 呼叫 sendmsg(),會讓 ctx->merge 停在 true,但最後一個 scatterlist 的 cur 卻變成零,於是核心用 sgl->sg + sgl->cur - 1 算出的位址落在陣列邊界之外的 sg[-1]。這條在 crypto/af_alg.c 裡潛伏了十四年的競爭條件被 STAR Labs 研究員 Muhammad Alifa Ramdhan 編號為 CVE-2025-39964,本文於 2026 年 9 月 25 日在 IDNSEC 公開完整分析,該漏洞曾透過 Google kernelCTF 拿下 $113,337.00 美元獎金。

漏洞機制

AF_ALG 讓一般使用者程式透過 socket(AF_ALG, ...) 直接呼叫核心的加解密功能。使用者呼叫 sendmsg() 時,核心不會立刻加密,而是先把資料收進 struct af_alg_ctx 底下的 tsgl_list,每個節點是一個 struct af_alg_tsgl:

struct af_alg_tsgl {
    struct list_head list;
    unsigned int cur;
    struct scatterlist sg[];
};

cur 記錄目前用了幾個 scatterlist 項目,正常情況下最後一項是 sgl->sg + sgl->cur - 1。當某次寫入沒有填滿一整個分頁時,核心會把 ctx->merge 設成 true,讓下一次 sendmsg() 直接把資料接到同一個 scatterlist 尾端,藉此省下配置新分頁的成本。這個邏輯隱含一個前提:只要 ctx->merge 為 true,最後一個 af_alg_tsgl 就一定至少有一個項目,cur 不可能是零。

問題出在 af_alg_sendmsg() 呼叫 lock_sock() 之後,若送出緩衝區滿了,會進入 af_alg_wait_for_wmem() 等待,而等待期間 sk_wait_event() 會先 release_sock() 再重新 lock_sock()。這段等待讓兩個執行緒可以交錯執行:執行緒 A 在等待時釋放了鎖,執行緒 B 趁機把最後一個 af_alg_tsgl 填滿並設定 ctx->merge = true;執行緒 A 醒來後發現該物件已滿,於是配置一個新的 af_alg_tsgl(cur = 0),但因為刻意傳入無效的使用者位址讓 memcpy_from_msg() 失敗而提前返回——此時 ctx->merge 仍是 true,而新的最後節點 cur 卻是零。下一次 sendmsg() 再讀到 ctx->merge 就會算出 sg = sgl->sg + 0 - 1 = &sgl->sg[-1],讀到目前物件前面 0x18 位元組(一個 scatterlist 大小 0x20)處、屬於上一個堆積物件的資料。

研究團隊接著用堆積噴灑控制 sg[-1].page_link,讓核心把偽造的 struct page 位址當成複製目的地,交給 memcpy_from_msg()(實際呼叫 raw_copy_from_user())寫入。由於 access_ok() 只檢查來源位址,不檢查目的地,寫入失敗時只會回傳 -EFAULT 而不會讓核心當機,等同一個可反覆試探的 oracle。團隊靠這個 oracle 定位出目的地頁面,最終把任意寫導向 core_pattern,讓核心以 root 權限執行崩潰處理程式,達成本機提權;因為 AF_ALG 在容器內同樣可觸及主機核心,同一條路徑也能逃出 Docker 容器取得主機 root。

受影響版本

易受攻擊的程式碼可回溯到 2011 年隨 Linux 2.6.38 一起加入的提交 8ff590903d5f(crypto: algif_skcipher 的使用者空間介面),研究者以 v6.12.44 作為分析與利用開發的版本。文章指出,「受影響的核心會一直維持漏洞狀態,直到 2025 年的修補為止,實際情況仍取決於各家發行版的回補與組態」。任何允許一般使用者觸及 AF_ALG socket API 的系統都在範圍內,包括與主機共用核心的容器環境——這正是多租戶主機或容器平台需要優先確認核心版本與修補狀態的原因。作者也特別區分:2026 年被揭露、並在 2026 Pwnie Awards 拿下最佳提權漏洞獎的 Copy Fail,是 AEAD 路徑上另一個獨立的邏輯錯誤,與本篇的併發寫入競爭並非同一個洞。

修補與緩解

上游修補提交 crypto: af_alg - Disallow concurrent writes in af_alg_sendmsg(1b34cbbf4f011a121ef7b2d7d6e6920a036d5285,作者 Herbert Xu,2025-09-18 進入 stable 樹)不是補一個 cur == 0 的檢查,而是直接禁止同一個 socket 有兩個並行寫入者:

// af_alg_sendmsg() 開頭
lock_sock(sk);
if (ctx->write) {
    release_sock(sk);
    return -EBUSY;
}
ctx->write = true;
// ... 函式結尾
ctx->write = false;

struct af_alg_ctx 也把 more、merge、enc、init 從獨立的 bool 欄位改成位元欄位並新增 write:1。第二個執行緒若在第一個尚未完成 sendmsg() 前搶著寫入,會直接收到 -EBUSY,不會再有機會看到中間態的 ctx->merge 與 cur 組合。受影響環境的維運者應確認核心是否已包含這個提交(或發行版對應的回補),特別是提供裸機租戶存取、或允許容器內程式呼叫 socket(AF_ALG, ...) 的主機;使用 seccomp 或 LSM 政策封鎖非必要工作負載的 AF_ALG 存取,也能在還沒套上修補前降低暴露面。

原始來源:IDNSEC:How I Found a $113,337 AF_ALG Linux Local Privilege Escalation Before Copy Fail、kernel.org:crypto: af_alg - Disallow concurrent writes in af_alg_sendmsg


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