CVE-2026-43499,代號 GhostLock,是 Nebula Security 於 2026 年 7 月 7 日公開的 Linux kernel 本地權限提升漏洞。核心是 kernel/locking/rtmutex.c 裡的 remove_waiter() 對錯了任務物件,造成 futex priority inheritance 路徑上的 stack use-after-free。這段程式從 2011 年 5 月的 Linux 2.6.39 就存在,至今 15 年,主線一路到 7.1 才把它修掉。CVSS 7.8 看起來不算頂格,但公開 PoC 的 97% 穩定率跟 5 秒內拿 root 的實測時間,讓這個洞的實際威脅比分數本身高一大截。對每一臺跑 Linux 的 VPS、每一個把 CI runner 或多租戶服務放進容器的環境,這都是本週不能拖的補丁。
影響範圍為什麼會這麼大
GhostLock 的直接觸發前提只有兩個:一個是攻擊者要能在目標系統上執行本地程式碼,另一個是 kernel 開了 CONFIG_FUTEX_PI。第二個條件實際上等於「所有主流發行版全中」——glibc 的 PI mutex、robust futex、部分 pthread 特性都倚賴這個 config,Debian、Ubuntu、AlmaLinux、Rocky、openSUSE、Arch 全都預設打開。
「本地帳號」這個條件聽起來像高門檻,但在 2026 年的雲環境下,它幾乎等於零門檻。共用 VPS、多租戶 Kubernetes 節點、GitHub Actions 的自架 runner、CI/CD pipeline 執行任意 PR 的 sandbox、shell 教學平臺、SaaS 產品開放的 web IDE,任何一種容許外部使用者跑程式的服務,都算「本地」。Nebula 公佈的 PoC 明確標示可從容器內部觸發、逃逸到宿主,也就是「一般容器隔離」不能擋。這點對把 Docker 當成安全邊界使用的團隊尤其致命。
漏洞觸發不需要 CAP_SYS_ADMIN、不需要 unprivileged user namespace、不需要繞過 seccomp 常見設定。真正被封鎖的攻擊面只有一個:kernel 完全不開放 futex 系統呼叫的環境。這在實務上不存在,因為 futex 是 glibc 執行緒同步的基礎,禁掉等於禁掉大部分應用程式。
remove_waiter 為什麼會清錯任務
要理解 GhostLock 的技術本質,得先看 futex PI 的 requeue 機制。FUTEX_WAIT_REQUEUE_PI 與 FUTEX_CMP_REQUEUE_PI 是為了 pthread_cond_wait() 這類「先等一個 futex、被喚醒後改等另一個 PI futex」的語意設計出來的。等待端 thread 掛在 f_wait 上,喚醒端用 FUTEX_CMP_REQUEUE_PI 把它搬到 f_pi_target 這條 PI 鏈上。搬運過程中,kernel 呼叫 rt_mutex_start_proxy_lock() 代替等待端去試著拿 rt_mutex。
remove_waiter() 原本的設計假設非常單純:一個 thread 自己 block 在某個 rt_mutex 上、後來自己解 block、自己清理。整段 helper 都用 current 這個當前執行 thread 指標去更新 pi_blocked_on、拆 pi_waiters 樹。這在 15 年前只有一種呼叫路徑時完全沒問題。
Requeue-PI 把這個假設打破了。當 requeuer thread 執行 rt_mutex_start_proxy_lock() 時遇到 -EDEADLK(例如剛好構成鎖環)、需要把剛剛加進去的 waiter 拆掉,這時候呼叫的仍然是 remove_waiter()。它會用 current 去清狀態,但 current 是 requeuer,不是那個真正被代理進 rt_mutex 的 waiter thread。清完之後,waiter thread 的 pi_blocked_on 還指向已經釋放的 stack 位置,waiter 的 rb_tree node 也留在 pi_waiters 上,變成一顆定時炸彈。
Linux 7.1 的修補用 waiter->task 拿到正確的 owner,並用 scoped_guard(raw_spinlock, &waiter_task->pi_lock) 把清理範圍鎖對地方。修補本身不到二十行,難在這條路徑十五年來從沒有人在 review 時把 current 跟 waiter->task 的差異看出來。
觸發鎖環:三個 futex、三個 thread
實際觸發要精心排出下列狀態:
- Waiter thread(A):先拿到 f_pi_chain 這個 PI futex 的 owner,接著呼叫
FUTEX_WAIT_REQUEUE_PI(f_wait → f_pi_target),掛在 f_wait 上。 - Owner thread(B):拿到 f_pi_target 的 owner,然後嘗試 lock f_pi_chain,會 block 起來——因為 f_pi_chain 的 owner 是 A。
- Main thread(C):對 f_wait 呼叫
FUTEX_CMP_REQUEUE_PI(f_wait → f_pi_target),把 A 搬到 f_pi_target 上。
搬運過程中 kernel 幫 A 代理鎖 f_pi_target,觸發 PI chain walk。此時鏈條變成:A → f_pi_target → B → f_pi_chain → A。這是一條完整的死鎖環,rt_mutex_start_proxy_lock() 偵測到會回傳 -EDEADLK,並呼叫 remove_waiter() 拆狀態。而 remove_waiter() 就在這一步對錯了 task。
觸發本身不需要 root。三個 thread、三個 futex、正確的順序,就這樣。Nebula 的 PoC 把整條鏈壓進大約 400 行 C,測試 97% 穩定率、單次執行約 5 秒。
從 stack UAF 走到宿主 root:IonStack Part II
拿到 UAF 只是起點。GhostLock 之所以被 Google 的 kernelCTF 給到 92,337 美元,是因為 Nebula 把它變成穩定的 root 攻擊路徑。整條逃逸鏈值得每一位系統管理員理解,才知道為什麼「等看看有沒有實際攻擊」是壞策略。
第一步是 stack 回填。waiter thread 從 FUTEX_WAIT_REQUEUE_PI 返回後,kernel stack frame 釋放。攻擊者用 PR_SET_MM_MAP 這個系統呼叫,把控制得住的位元組寫進去,同時把記憶體排成一個假的 rt_mutex_waiter 結構。這一步關鍵在能不能穩定「搶到」同一段 stack 空間,PoC 用 CPU pinning 跟連續觸發把成功率拉到 97%。
第二步是任意寫入原語(arbitrary write primitive)。假的 waiter 被留在 pi_waiters 這棵紅黑樹裡,另一個 thread 呼叫解鎖時會觸發 rb-tree erase,寫入操作會落到攻擊者指定的位址。Nebula 把這一寫瞄準 inet6_protos[IPPROTO_UDP],把 UDPv6 handler 換成指向 CPU entry area(CEA)的假處理函式。
第三步是控制流劫持。從本機發一個 loopback IPv6 UDP 封包,kernel 收到後從 inet6_protos 查 handler、跳到 CEA 上的假 handler,執行攻擊者放好的 ROP chain。
第四步是提權。ROP chain 直接改 /proc/sys/kernel/core_pattern 的權限、寫入一個 pipe 命令,之後任何一個 crash 的 process 都會用 root 執行那個 pipe 命令。等於「有沒有 root」變成「有沒有一個會 crash 的 process」——這在多租戶容器裡永遠都有。
第五步是命名空間逃逸。一旦有 root,PID / mount / network namespace 全都能爬出去,容器邊界形同虛設。整條鏈完全在 unprivileged 使用者權限內啟動,不需要任何 CAP、不需要 user namespace、不需要 privileged 容器。
修補進度:各家發行版現在到哪
上游 kernel 7.1 是完整修補的第一個穩定版。實務上大多數系統跑的是發行版打包的 kernel,各家的節奏都不一樣。
RHEL 系(AlmaLinux、Rocky、Oracle Linux)已經釋出 backport:AlmaLinux 8 要升到 kernel-4.18.0-553.141.2.el8_10 以上,AlmaLinux 9 要 kernel-5.14.0-687.24.1.el9_8,AlmaLinux 10 要 kernel-6.12.0-211.32.1.el10_2。指令就是 dnf clean metadata && dnf upgrade 加 reboot,重開機後 uname -r 對一下版本號。
Debian 系裡,Debian 13 Trixie 已經進 stable-security,apt update && apt full-upgrade 就會把 kernel 拉起來。Ubuntu 的節奏比較亂:24.04 LTS、22.04 LTS 起先都還在 in-progress 狀態,到 7 月中之後才把 HWE kernel 補齊,apt list --upgradable | grep linux-image 檢查一下確保裝到最新的 -generic。20.04 LTS 已進入 ESM,沒有 Ubuntu Pro 訂閱的話這一版拿不到修補,這種情境該考慮的是升上 22.04 或 24.04,而不是留在 20.04 想著撐過去。
自己編 kernel 的環境更要注意:光把源碼拉到 7.1 還不夠。原始 patch 曾經在 rollback 邏輯上引入第二個 crash 路徑(後來被指派為 CVE-2026-53166),完整修補要等 7.1 的 stable 更新把 follow-up commit 也吸收進去。cherry-pick 單一 commit 的環境務必把兩個 commit 一起帶。
CoreOS、Bottlerocket、Talos Linux 這類 immutable OS 走的是整包 image 更新,發行商已經在 7 月 10 日前後推出更新 image,直接走既有的自動更新機制。
VPS 管理員今晚該做的動作
升級 kernel 並重開機——這是唯一有效的緩解手段。沒有 workaround、沒有半吊子的減緩措施。CloudLinux、Ubuntu Pro、TuxCare、Oracle Ksplice 這類 livepatch 服務可以做到不重開機打 patch,但沒訂閱這類服務的環境,就是老老實實排維護時段重開。
盤點多租戶暴露面——名下所有跑 Docker、Kubernetes、Podman、LXC 的節點都算,尤其是允許外部 image、外部 build script、外部 PR 執行的環境。GitHub Actions、GitLab Runner、Jenkins 的執行節點是最高優先級,因為攻擊者能用 workflow 或 pipeline 直接送 PoC 進去。
檢查未修的 uptime——uptime 顯示很久沒重開的 host 就是壓力最大的一批。這些機器往往同時跑最多服務、擋不了排維護。找出來、排時段、動手升。
評估 seccomp 與 landlock 的實際效用——Nebula 已明說 seccomp 無法完全擋,因為 futex 是常見系統呼叫,正常應用不能封。真的想再加一層,可以在應用程式的 seccomp profile 裡把 futex_waitv、FUTEX_LOCK_PI、FUTEX_CMP_REQUEUE_PI 這幾個 op code 加進 deny list,但要驗證這不會打掛 glibc 的 PI mutex。這是「補丁補不上時的暫時止血」,不是替代方案。
打開 kernel 硬化 config——RANDOMIZE_KSTACK_OFFSET 跟 STATIC_USERMODE_HELPER 會讓 PoC 的 stack 回填難度上升,但不能保證擋下。長期上這兩個 config 都該打開,短期不能當救命稻草。
檢查稽核紀錄——這個洞不會留下明顯的 IOC。Nebula 沒公佈任何攻擊指紋,因為觸發用的是完全合法的 futex 呼叫。實務上能做的是用 eBPF probe 監控高頻率的 FUTEX_WAIT_REQUEUE_PI 加 FUTEX_CMP_REQUEUE_PI 混合呼叫、監控 /proc/sys/kernel/core_pattern 被非 root 改動、監控非預期的 inet6_protos 修改。這些指標在正常應用裡本來就罕見,噪音低但需要事先部署。
這個洞把「共用 kernel」的老問題再放大一次
GhostLock 不是特殊 bug,而是「多租戶共用 kernel」這個設計本質的又一次警告。容器隔離依賴 kernel 正確處理權限邊界;kernel 只要一條路徑錯了,容器邊界就等同不存在。同樣的邏輯過去在 Dirty COW、Dirty Pipe、CVE-2026-31431 上都成立過,未來還會繼續成立。
務實的結論很直接:把安全邊界從 kernel namespace 抬到 hypervisor。Firecracker、Cloud Hypervisor、KVM 這類 VM 級隔離,是唯一能在 kernel 本地權限提升面前站得住的層級。這也是為什麼在同一臺實體機上多租戶時,VPS(每租戶一顆獨立 kernel)的隔離強度天然高於容器(共用 kernel),而多層防護的做法會把外部租戶的容器再包一層 microVM。
NCSE Network 在臺灣是方電訊機房的 VPS,每一顆實例都跑在獨立 kernel 之上,租戶之間沒有共用 rt_mutex 這條路徑可以繞。搭載 Intel Gold CPU 與 NVMe SSD 的規格讓核心升級、reboot、livepatch 這些動作的維運窗口壓到最短,對想把公開服務、CI runner、外部 build sandbox 從共用容器抬升到獨立 VM 邊界的團隊,可以直接接上。想在這波 kernel 升級之後把架構順便重整一次,這是能落地的下一步。