應用程式熱補丁(三) 完整的設計與實現

2021-10-17 16:26:01 字數 4277 閱讀 7343

這些是組成應用程式熱補丁技術框架的關鍵部分,但是在生產環境中使用熱補丁技術還需要考慮適應現代軟體的屬性、熱補丁的安全性、以及在運營中對熱補丁的管理等等。

通過介紹ucloud應用程式熱補丁框架的設計理念和框架中各個元件,我們會解決以下實踐中遇到的問題:

介紹ucloud應用程式熱補丁框架之前,首先介紹一下我們為什麼研發和使用熱補丁技術。

目前主流的熱補丁技術,例如ksplice、kpatch、kgraft、以及後來的livepatch等都是特別針對linux核心的熱補丁技術,可以在不重啟系統的情況下,修復核心缺陷。我們一般稱為核心熱補丁。

ucloud使用了核心熱補丁修復了若干核心問題,避免了重啟系統導致的服務中斷,保證了作業系統本身的可用性。

在ucloud我們通過熱補丁修復了若干次qemu的缺陷和安全漏洞,極大提高了可用性和安全性。因此我們認為對於**改動較小的問題時,熱補丁是乙個完美的解決方案。

為什麼要自研應用程式熱補丁技術?答案也很簡單,我們無法找到乙個實用並且易用的應用程式熱補丁技術,同時也由於我們已經在核心熱補丁領域的具有一定的積累,所以決定敢為人先、自研應用程式熱補丁技術。

提出需求

介紹設計理念之前,首先應該提出應用程式熱補丁在ucloud雲平台的需求:

我們針對這些需求,設計出如下的應用程式熱補丁框架。

設計思路

或者簡單來說,我們要做到,拿到原始碼和patch就能通過工具自動生成熱補丁,熱補丁可以安全的打入執行的多執行緒應用程式中(不會引起程式的錯亂和崩潰),並且支援打入多個熱補丁。打入後的熱補丁可以被回滾取消,可以查詢當前應用程式中熱補丁的狀態和資訊。

框架元件

這個框架的設計我們通過以下元件實現:

負責通過patch和原始碼自動化生成熱補丁。

支援函式級別修復,不論本地函式還是全域性函式。

負責載入熱補丁到目標程序中,也負責管理熱補丁(類似於客戶端程式)。

目標程序支援linux x86_64、多執行緒等。

支援熱補丁安全檢查。

支援對熱補丁狀態的操作(例如載入、解除安裝、啟用、回滾查詢等等)。

負責記錄多個熱補丁的狀態和資訊,同時提供熱補丁通用操作。

作為熱補丁模組的通用執行時框架被loader載入到目標程序中。

loader對熱補丁狀態的操作最終由core runtime在目標程序空間中執行。

負責提供修復後的替換**和額外資訊。

被loader載入到目標程序中,註冊自己的資訊到core runtime

在啟用後使用自身包含的替換**代替有問題的函式。

元件之間協作如下圖所示,creator工具根據程式原始碼和patch生成熱補丁模組,然後loader將熱補丁模組載入到目標程序process的位址空間裡,最後熱補丁和通用執行時core runtime一起完成熱修復。

接下來分別講各個元件的實現:

creator

基於對多種核心熱補丁技術的理解,我們認為應用程式的熱補丁也是可以通過工具自動生成的。雖然相比核心,應用程式的格式更加複雜、編譯鏈結的過程也更不固定,但是自動生成熱補丁應該是可行的。

我們知道,編譯源**之後會生成目標檔案,將單個或多個目標檔案鏈結可以生成可執行檔案。目標檔案和可執行檔案都是elf格式(executable and linkable format)。elf是一種標準且通用的檔案格式,linux上的可執行檔案、目標檔案、庫、core dump都是elf。

creator工具根據elf標準的格式,解析修復前後的目標檔案,找到前後不同的函式,提取出差異(包括改變和新增的函式),連同差異本身的屬性資訊,生成乙個動態鏈結庫格式的熱補丁。如下圖所示:

之前的文章介紹過二進位制比較生成熱補丁替換**,這裡不再贅述。

loader

loader工具作為乙個客戶端程式,操作目標程序process,包括熱補丁的載入、啟用、回滾、解除安裝、檢視等。如下所示:

loader利用了ptrace呼叫。loader通過ptrace可以對process的記憶體、暫存器進行讀寫,改變process的執行狀態,也可以捕獲process的訊號。這樣loader可以停止process的執行,並根據amd64 abi對記憶體和暫存器進行修改,使process執行dlopen等函式,載入熱補丁到process的位址空間中,或者執行其他熱補丁的操作。熱補丁被載入之後,在/proc/pid/maps檔案中可以看到。

loader如何利用ptrace載入熱補丁在之前的文章中有詳細描述,不再贅述。

在停止所有執行緒的時候,首先需要得到全部的執行緒資訊,可以通過libthread_db庫與程序中libc進行互動得到執行緒的資訊,也可以通過/proc/pid/tasks/目錄從核心中直接得到執行緒的資訊。在停止所有執行緒之後,需要再次獲取所有執行緒資訊,檢視是否有新增執行緒,如果有需要停止新增執行緒。重複以上動作直到沒有新執行緒出現。

core runtime

在乙個程序的生命週期中,可能需要多次熱補丁修復,同時多個熱補丁也會使用一些通用的功能,因此需要乙個通用的核心模組來提供通用功能,並且記錄程序中每個熱補丁的資訊。這個通用模組作為乙個動態鏈結庫,我們叫做core runtime。

loader在載入熱補丁時,首先需要載入core runtime到程序的位址空間,對程序而言,core runtime只需要載入一次。

在熱補丁被載入到程序的位址空間後,通過建構函式,首先向core runtime提供自己的資訊,註冊到core runtime裡,然後將熱補丁中差異函式的需要重定向的部分手動計算重定向。在啟用熱補丁的時候,core runtime會根據熱補丁註冊時得到的資訊,儲存舊函式,並把舊函式入口位置替換成跳轉到新的函式的機器碼,完成熱修復。如下所示:

在回滾熱補丁的時候,core runtime把舊函式入口位置恢復,完成回滾。

core runtime同時可以管理多個熱補丁,以熱補丁的名字作為id,區分不同的熱補丁,記錄必要的資訊。

如下所示:

熱補丁(補丁本身)

這裡的熱補丁指的是狹義上的作為動態鏈結庫被loader載入到目標程序process中的熱補丁。

熱補丁由creator產生,包含了替換**和一些動態資訊(比如新舊函式的位址、大小、重定向資訊等)。熱補丁被載入後,包含的函式和變數就存在於目標程序的位址空間中。熱補丁啟用以後,所有對老函式的訪問,都會重定向到熱補丁位址範圍內的新函式。

如下所示:

creator、loader、core runtime、熱補丁這四者構成了ucloud熱補丁技術框架,這四個元件相輔相成,互相協作完成熱補丁。

creator負責生成熱補丁,loader負責熱補丁的程序外管理(包括載入、解除安裝、啟用、回滾熱補丁等),core runtime負責熱補丁的程序內管理(記錄熱補丁、備份舊函式、恢復舊函式等)。雖然是四個元件,但是都必須遵守同乙個熱補丁規格標準,這樣才能共同完成熱補丁的工作。

通過這個框架,極大降低了我們製作熱補丁、打入熱補丁和運營熱補丁的難度。

例如,乙個qemu安全漏洞修復的流程可以簡化為:

creator通過qemu原始碼和漏洞修復patch生成熱補丁。

熱補丁被loader打入正在執行的應用程式中(載入並且啟用)。

(可選)對執行中的應用程式查詢熱補丁的狀態和資訊。

(可選)對已經打入的熱補丁進行回滾和解除安裝。

值得指出的是,目前不是全部patch都可以自動生成熱補丁,原因是極少部分由於程式修改複雜,但是可以通過手動修改patch簡化**或者簡化邏輯做到可以自動生成熱補丁。大約90%的patch在無需修改的情況下都能自動生成熱補丁。

另外,目前ucloud應用程式熱補丁技術支援linux c語言程式,但對於其他編譯型語言解決思路基本一致(例如c++等)。

在ucloud,我們利用應用程式熱補丁修復了若干緊急安全漏洞和缺陷,在關鍵時刻迅速解決問題,相比於傳統的軟體公升級方式,解決問題更加及時。

Web應用程式與桌面應用程式的區別

web delphi 伺服器網路 internet access 如果都是用.net做的話,桌面程式需要開發伺服器端和客戶端兩塊程式,電腦都要安裝.net framework,b s形式的話,只用做伺服器端。但兩者桌面應用可能軟體介面更好控制一些,web形式客戶端的螢幕就不太好空,一般滿足1024 ...

Web應用程式與桌面應用程式的區別

web delphi 伺服器網路 internet access 如果都是用.net做的話,桌面程式需要開發伺服器端和客戶端兩塊程式,電腦都要安裝.net framework,b s形式的話,只用做伺服器端。但兩者桌面應用可能軟體介面更好控制一些,web形式客戶端的螢幕就不太好空,一般滿足1024 ...

應用程式物件正在關閉 設計您的互動應用程式

設計您的互動應用程式 如何建立單獨的互動應用程式 摘要 本文將解釋如何建立互動式應用程式,以及應該從互動式應用程式基類中覆蓋的方法 什麼是互動應用程式?要派生以建立應用程式主視窗和演示文稿的catdlgdocument類 要派生以建立對話方塊所需的臨時視窗的catdlgdialog類。下圖顯示了所涉...