CVE-2026-43494 / PinTheft:Linux RDS 與 io_uring 組合出的本地提權風險

整理 CVE-2026-43494 / PinTheft 的核心資訊:它如何由 Linux RDS zerocopy 引用計數問題與 io_uring fixed buffer 組合成本地提權鏈,以及管理員應如何判斷前置條件、降低暴露面並等待發行版修復。

CVE-2026-43494 是一個 Linux 核心本地權限提升風險,外界也用 PinTheft 來稱呼相關利用鏈。它的關鍵不在遠端入口,而在於本地低權限使用者能否同時碰到 RDS zerocopy、io_uring fixed buffer、可讀 SUID-root 程式和合適的核心版本。

需要先說明一個編號細節:Unclecheng-li/poc-lab 倉庫目錄名寫的是 CVE-2026-43494 PinTheft,README 標題裡又寫了 QVD-2026-27616 - PinTheft。從公開 CVE 條目和第三方通告來看,CVE-2026-43494 指向的是 Linux kernel RDS zerocopy 中 op_nents 未正確重置引發的 double-free / 引用計數異常問題;QVD-2026-27616 更像是奇安信風險通告編號。實際排查時建議同時記錄這兩個標識,但以發行版安全公告和核心補丁狀態為準。

漏洞核心是什麼?

這個問題出現在 Linux RDS,也就是 Reliable Datagram Sockets 的 zerocopy 發送路徑中。公開描述裡的關鍵函式是:

1
2
rds_message_zcopy_from_user()
rds_message_purge()

iov_iter_get_pages2()rds_message_zcopy_from_user() 中失敗時,已經 pin 住的頁面會先被錯誤路徑釋放;但相關 op_nents 資訊沒有被正確清零,後續 rds_message_purge() 仍可能按殘留條目再釋放一次。結果就是同一批頁面引用被多減,形成可被利用的引用計數錯誤。

單看 RDS bug,它是核心記憶體管理裡的錯誤路徑問題。PinTheft 的危險之處在於利用鏈把它和 io_uring 固定緩衝區機制連了起來:io_uring 仍保存著舊的 struct page *,而頁面本身已經被釋放並重新分配給其他用途。PoC 進一步把這個狀態引向 SUID-root 程式的 page cache 覆寫,最終達到本地提權。

為什麼叫 PinTheft

io_uring REGISTER_BUFFERS 會固定使用者頁。對普通頁面來說,FOLL_PIN 並不只是簡單增加一個引用,而是透過較大的 bias 增加 page refcount。公開 PoC 中使用了 GUP_PIN_COUNTING_BIAS = 1024 這個概念。

PinTheft 這個名字的意思是:攻擊鏈透過 RDS zerocopy 的失敗路徑,一次次「偷走」這些 pin 引用。等引用被耗掉後,io_uring 仍以為自己持有有效頁面,但該實體頁已經可以被釋放並被 page cache 重新占用。

這類漏洞容易被誤讀成「直接改了磁碟上的 /usr/bin/su」。更準確的說法是:利用鏈嘗試覆寫的是記憶體中的 page cache。檔案本體不一定被寫回磁碟,但核心執行該 SUID 程式時可能從被污染的頁快取取指令,從而執行攻擊載荷。

觸發條件並不寬

這不是一個「任意 Linux 伺服器都能遠端打」的漏洞。公開資訊顯示,利用鏈至少依賴這些條件:

  • 核心啟用了 CONFIG_RDSCONFIG_RDS_TCP
  • 系統啟用了 CONFIG_IO_URING,且 kernel.io_uring_disabled=0
  • rds / rds_tcp 模組已經載入,或低權限使用者可以觸發自動載入。
  • 本地存在可讀的 SUID-root 二進位程式,例如 /usr/bin/su/usr/bin/passwd/usr/bin/pkexec
  • 公開 PoC 還依賴較新的 IORING_REGISTER_CLONE_BUFFERS API,CloudLinux 的分析提到公共 PoC 更偏向 kernel 6.13 及以上形態。

只要其中一環不成立,公開鏈路就會斷掉。比如很多 RHEL 系發行版預設不編譯 RDS,Ubuntu 舊核心可能缺少 PoC 需要的 io_uring clone buffer API,部分環境也會限制非特權使用者自動載入 RDS 模組。

一分鐘自查

先看核心設定:

1
2
zgrep -E "CONFIG_(RDS|RDS_TCP|IO_URING)" /proc/config.gz 2>/dev/null \
  || grep -E "CONFIG_(RDS|RDS_TCP|IO_URING)" /boot/config-$(uname -r)

再看 io_uring 是否被禁用:

1
cat /proc/sys/kernel/io_uring_disabled 2>/dev/null

常見含義可以按這個思路理解:

  • 0:允許使用,風險面最大。
  • 1:限制非特權使用者使用,具體行為看核心版本和發行版策略。
  • 2:禁用 io_uring

檢查 RDS 模組是否存在、是否可載入:

1
2
lsmod | grep -E "^rds|^rds_tcp"
modprobe -n -v rds_tcp 2>&1 | head -3

如果 CONFIG_RDSnot set,或者系統根本沒有 rds_tcp 模組,通常就無法走到這個 bug。反過來,如果 RDS 可用、io_uring 未禁用、系統又是較新的通用核心,就應該提高優先級繼續確認發行版修復狀態。

哪些機器更值得優先看?

優先排查這些環境:

  1. 多使用者 Linux 主機、教學機、跳板機、共享開發機。
  2. 容器宿主機,尤其是允許不可信本地使用者或較寬鬆容器逃逸面的環境。
  3. 開啟較新 mainline / rolling kernel 的桌面或伺服器,例如 Arch 一類滾動發行版。
  4. HPC、Oracle RAC 或其他可能真實使用 RDS 的場景。
  5. 允許非特權使用者執行大量本地程式碼的 CI worker、建置機和實驗環境。

普通 Web 服務如果只有受控服務帳號執行應用,並且 RDS 未啟用,實際風險會低很多。但「低很多」不等於不用處理:核心本地提權的典型影響是攻擊者先透過 Web、SSH、CI、容器或應用漏洞拿到低權限,再用本地提權擴大控制面。

臨時緩解建議

正式修復仍應以發行版核心更新為準。補丁、回溯版本和受影響範圍需要看 Debian、Ubuntu、RHEL、AlmaLinux、Rocky Linux、SUSE、Arch、雲廠商或容器基礎映像各自的安全公告,不要只按上游版本號判斷。

在等待補丁或無法馬上重啟核心時,可以按環境選擇臨時措施:

1
2
3
4
5
# 如果業務不依賴 RDS,可阻止相關模組載入
sudo sh -c "printf 'install rds /bin/false\ninstall rds_tcp /bin/false\ninstall rds_rdma /bin/false\n' > /etc/modprobe.d/pintheft.conf"
sudo rmmod rds_tcp 2>/dev/null
sudo rmmod rds_rdma 2>/dev/null
sudo rmmod rds 2>/dev/null

如果業務不依賴 io_uring,也可以考慮禁用或限制它:

1
sudo sysctl -w kernel.io_uring_disabled=2

持久化設定需要寫入對應的 /etc/sysctl.d/*.conf。不過這一步要謹慎,現代資料庫、代理、執行時或高效能 I/O 程式可能使用 io_uring;生產環境修改前最好先確認業務依賴。

修復後怎麼驗證

升級核心後,不要只看套件管理器輸出成功。建議確認三件事:

1
2
3
uname -a
cat /proc/sys/kernel/io_uring_disabled 2>/dev/null
modprobe -n -v rds_tcp 2>&1 | head -3

如果發行版公告明確寫明已修復 CVE-2026-43494,即使 uname -r 看起來不是最新上游版本,也可能是已經回溯補丁的穩定核心。反過來,如果核心來源是自行編譯、第三方倉庫、雲市場映像或容器宿主機模板,就要繼續核對補丁 commit 和建置時間。

參考資訊

记录并分享
使用 Hugo 建立
主題 StackJimmy 設計