安全研究機構 Calif 的研究人員 Andrew Griffiths 於 2026 年 10 月 16 日發表研究,指出 OpenBSD 中存在一個可追溯至約 37 年前原始 BSD 原始碼的漏洞。該漏洞源於共享記憶體附加計數器(shared memory attachment counter)被定義為有符號 16 位短整數(signed 16-bit short)。當程序反覆 fork 並附加共享記憶體記錄時,該計數器可能超過最大值 32,767 並溢出為負值。這種整數溢出結合競態條件可導致釋放後使用(use-after-free),並與內核中另一個獨立的越界寫入漏洞結合,實現本地權限提升至 root。相關問題已透過 OpenBSD 勘誤 026 和 018 分別修復。

研究團隊成功在啟用 KARL、SMAP 和 SMEP 保護機制的 OpenBSD 環境中,無需依賴資訊洩露漏洞即取得本地 root 權限。利用路徑包括:映射 127 個 SysV 共享記憶體段並透過 munmap() 取消映射,接著 fork 259 個進程以將共享記憶體附加計數包裝為 -32,643;利用 sysctl(KERN_MALLOCSTATS) 的指標進行堆佈局整理;在一個進程中使用 IPC_RMID 贏得競態條件,同時在輔助進程中附加一個大小混淆的新共享記憶體段;對齊 IP 套接字分配並將 IP_MULTICAST_TTL 設為非預設值 2,以分配一個持久的 16 字節 struct ip_moptions,其最後一個字節打包了兩個 16 位計數器;觸發條件性的 -1 越界寫入以覆蓋成員數量及最大成員數量欄位;關閉套接字以遍歷群組成員,觸發原子遞減操作兩次修改 PTE 自引用映射,將其從用戶模式可訪問切換為超級用戶模式可訪問,從而通過覆蓋可預測的內核指標實現內核代碼執行;最後清理共享記憶體計數並恢復被覆蓋的內核指標以獲得 root shell。

該漏洞利用最終通過「write what where」原語獲得代碼執行權,其中 write 由 TAILQ_REMOVE 引起,what 是用戶空間記憶體映射(使其對超級用戶模式可訪問以繞過 SMAP/SMEP),where 是可預測的內核指標位置。儘管 OpenBSD 的 KARL 通過重新連結內核二進制文件來隨機化函數和數據地址,但其內核記憶體分配器(包括啟動時分配器和最佳適配分配器)缺乏基址隨機化,導致早期啟動分配在相同硬體上跨啟動保持一致的可預測位置。當這些可預測的結構分配包含函數指標時,便成為理想的利用目標,例如該漏洞可靠地針對 lo0 和 enc0 的 ioctl 處理程序。

除了上述勘誤修復外,研究還提出了幾種緩解措施:首先,實施安全解鏈接(safe-unlinking),在執行 unlink 記憶體寫入前檢查雙向鏈表不變量,若違反則調用 abort() 或 panic() 以防止記憶體損壞,FreeBSD 和 NetBSD 已在 sys/queue.h 中實現此技術;其次,隨機化自引用 PTE 映射的分配地址,通過在啟動時使用隨機字節選擇 PML4 槽位(320 + (random_byte & 127))並在那裡安裝遞歸條目,使 PTE_BASE 成為運行時表達式,從而使目標原子遞減位置變得不可預測;第三,通過隨機化啟動時的基址和運行時的分配順序使內核分配器非確定性,其中基址隨機化幾乎無成本,而運行時隨機化會帶來一些開銷。此外,還提到了利用編譯器特性如數組邊界_sanitizer_(array bounds sanitizer)來消除固定大小數組的越界訪問,以及 Alloc Tokens 來隔離包含指針的分配與非指針分配,從而使溢出更難被利用。

事件背景

OpenBSD 自成立以來一直倡導主動安全,包括源代碼審計、替換不安全 API、高級密碼哈希、加密、權限分離、沙箱化,以及通過 ASLR 和 W^X 實現的記憶體安全,經常為系統和網絡加固設定標準。該漏洞的根源可追溯至約 37 年前的原始 BSD 源碼,其中 shm_nattch 被定義為短整數。

社群觀察

社群討論中,用戶 [phendrenad2] 指出,該漏洞似乎在 1999 年 8 月 NetBSD 重寫該代碼時被意外修復。用戶 [ozereray1] 評論稱,一個漏洞能在審核最嚴格的代碼庫之一中存活 37 年,顯示了某些內核漏洞僅靠代碼審查難以發現,並質疑模糊測試或靜態分析是否現實上能發現這類漏洞,還是需要人類思考利用原語才能發現。用戶 [bch] 則對 OpenBSD 風格的圖形表示讚賞,並期待主題曲。