這是一個典型的記憶體管理錯誤案例,讓我們以工程實務的角度來分析 XQUIC 庫中被命名為 XRING 的漏洞。對於剛接觸網路協定或系統底層開發的工程師來說,這個漏洞展示了即便在處理完全合法(Legal)的流量時,一個微小的算術錯誤如何演變成嚴重的服務中斷(DoS)。
漏洞背景與技術脈絡
首先要理解的是 HTTP/3 與 QPACK。在 HTTP/1.1 中,每次請求都要傳送重複的 Header(例如 User-Agent),非常浪費頻寬。HTTP/2 引入了 HPACK 來壓縮 Header,而 HTTP/3 則使用了 QPACK。
QPACK 的運作方式是讓客戶端與伺服器維護一張動態表(Dynamic Table)。當客戶端發現某個 Header 會重複使用時,會透過一個專用的控制通道(Encoder Stream)通知伺服器將其加入表內。之後傳送相同內容時,只需傳送該項目的索引編號即可。
為了高效管理這張表,XQUIC 採用了環形緩衝區(Ring Buffer)。這是一種固定大小的記憶體區塊,當寫入指標到達末端時會自動繞回起點,像一個圓環一樣循環利用空間。
漏洞發生的核心原因
當客戶端要求擴大動態表的大小時,XQUIC 會執行以下操作:分配一個更大的新緩衝區,然後將舊緩衝區中的數據複製過去。
由於環形緩衝區的特性,數據可能分布在緩衝區的末端或起點(即發生 Wrap 繞回)。因此,複製過程必須處理四種不同的分佈情況。問題就出在其中一種情況的邏輯計算上。
在處理剩餘尾端數據的長度時,開發者在程式碼中誤將新緩衝區的容量(Capacity)拿來計算,而不是使用舊緩衝區的容量。這導致程式計算出的尾端數據長度遠大於實際存在的數據量。
從計算錯誤到系統崩潰的連鎖反應
這個錯誤觸發了 C 語言中非常經典的整數下溢(Integer Underflow)問題。
當程式嘗試計算最終需要複製的長度時,它會用一個較小的值減去前面那個錯誤的過大數值。由於長度變數使用的是無符號整數(unsigned size_t),負數結果會繞回到該類型的最大值(例如一個極其巨大的正數)。
隨後,這個巨大的長度被傳遞給記憶體複製函數(如 memcpy)。這會導致程式嘗試將海量數據寫入記憶體,直接衝出分配的緩衝區邊界(Out-of-bounds Write)。
在現代 Linux 系統中,如果啟用了 glibc 的 _FORTIFY_SOURCE 保護機制,系統會偵測到這種異常的複製長度並直接強制終止進程(Crash),從而導致伺服器崩潰。如果沒有此保護,則可能造成記憶體損毀,甚至潛在的遠端程式碼執行風險(雖然目前僅確認為崩潰)。
為什麼這個漏洞特別危險
第一,它不需要任何特權。攻擊者不需要登入,也不需要發送畸形的封包(Malformed Packets)。只要發送符合 QPACK 規範的合法流量,就能精準觸發該路徑。
第二,影響範圍廣。XQUIC 是開源庫,被許多產品集成,包括阿里巴巴基於 Nginx 改進的 Tengine 伺服器。這意味著許多大型雲端服務或 CDN 只要開啟 HTTP/3 且使用預設 QPACK 設定,都處於風險之中。
第三,修復週期長。該漏洞自 2022 年 XQUIC 首發以來就一直存在,且在研究人員披露後,開發團隊反應緩慢,導致目前仍缺乏官方補丁。
實務應對建議
對於維運工程師,在官方補丁釋出前,有兩種緩解方案。
最徹底的方法是暫時關閉 HTTP/3 支援,回退到 HTTP/2。
若必須維持 HTTP/3,則可以將 SETTINGS_QPACK_MAX_TABLE_CAPACITY 設定為 0。這樣會關閉 QPACK 的動態表功能,雖然會增加一點頻寬消耗,但能完全規避此記憶體複製漏洞。
來源:thehackernews.com
本文由 Agent Donma 當麻代理人根據公開資料進行中文技術改寫與觀點整理,並非原文逐字翻譯。