龍星澧,黃傳波,胡曉勤
(1.四川大學(xué)網(wǎng)絡(luò)空間安全學(xué)院,成都 610065;2.成都云祺科技有限公司,成都 610041)
隨著云計算技術(shù)高速發(fā)展和企業(yè)信息化的不斷加速,數(shù)據(jù)安全逐漸成為大家越來越關(guān)注的內(nèi)容,而容災(zāi)備份作為保障數(shù)據(jù)安全的一個重要方式,也越來越受到重視。
持續(xù)性數(shù)據(jù)保護(hù)技術(shù)(Continuous Data Protection,CDP)是近年來容災(zāi)備份領(lǐng)域提出的一個全新概念。傳統(tǒng)數(shù)據(jù)保護(hù)方式一般為定時或手動備份,當(dāng)數(shù)據(jù)發(fā)生損壞時,該方式只能恢復(fù)到數(shù)據(jù)備份的時間點,而這期間的數(shù)據(jù)則會發(fā)生丟失。采用持續(xù)性數(shù)據(jù)保護(hù)技術(shù),則能連續(xù)捕獲并保存數(shù)據(jù)的變化,在數(shù)據(jù)發(fā)生損壞時,其恢復(fù)目標(biāo)點可以是任意時間,所以不會丟失數(shù)據(jù)。
服務(wù)器虛擬化技術(shù)是云計算中最核心的技術(shù),基于內(nèi)核的虛擬機(Kernel-Based Virtual Machine,KVM)是云計算中常用虛擬化技術(shù),這是一種內(nèi)建于Linux 系統(tǒng)的開源虛擬化技術(shù)解決方案。本文針對KVM 虛擬化技術(shù),提出了一種持續(xù)性數(shù)據(jù)保護(hù)方法,其能在KVM 虛擬機運行期間,連續(xù)地捕獲KVM 虛擬機產(chǎn)生的數(shù)據(jù),實現(xiàn)持續(xù)性數(shù)據(jù)保護(hù)。
常用的KVM 虛擬化分為KVM 部分與QEMU部分,KVM 部分通過KVM.ko 這個內(nèi)核模塊來實現(xiàn)核心虛擬化的功能,也就是CPU 和內(nèi)存的虛擬化;而QEMU 部分則提供了包括網(wǎng)卡在內(nèi)的其他硬件的虛擬化,其運行在用戶態(tài),作為一個應(yīng)用程序存在。兩個部分互相協(xié)作,形成一套完整的虛擬化技術(shù)。
當(dāng)KVM 虛擬化的guest 機要發(fā)起IO 請求時,guest 機首先會將指令發(fā)送給內(nèi)核中的KVM 內(nèi)核模塊,KVM 內(nèi)核模塊對指令進(jìn)行相應(yīng)處理后,會發(fā)送數(shù)據(jù)給應(yīng)用層的QEMU,QEMU 進(jìn)行處理后,在宿主機上完成最后的IO 操作。具體的流程如圖1所示。

圖1 KVM虛擬機架構(gòu)
由于KVM 虛擬機的IO 都是通過QEMU 執(zhí)行的,所以要對KVM 進(jìn)行持續(xù)性數(shù)據(jù)捕獲,就需要捕獲應(yīng)用程序QEMU 的IO。本文采用了Linux Hook 技術(shù)編寫IO 過濾驅(qū)動,對KVM 虛擬機數(shù)據(jù)進(jìn)行捕獲。
常見的Linux Hook 技術(shù)分為ring0 層Hook 和ring3 層Hook,其中ring0 層Hook 主要針對Linux系統(tǒng)內(nèi)核,通過編寫內(nèi)核模塊替換系統(tǒng)調(diào)用以及內(nèi)核函數(shù)來實現(xiàn)Hook。ring3 層hook 被分為了動態(tài)注入和靜態(tài)注入,靜態(tài)注入為程序還沒運行時,修改替換程序的.so 文件實現(xiàn);而動態(tài)注入則需要在程序運行時,動態(tài)地將函數(shù)地址替換為我們所需要的函數(shù)。
QEMU 在Linux 中采用的是Linux 標(biāo)準(zhǔn)IO 流程,其過程如圖2所示。

圖2 Linux IO流程
編寫IO 過濾驅(qū)動,首先需要確定過濾驅(qū)動的插入層次,常見過濾驅(qū)動一般在系統(tǒng)調(diào)用層、虛擬文件系統(tǒng)層或通用塊層編寫。
本文選取在系統(tǒng)調(diào)用層和應(yīng)用層分別編寫IO過濾驅(qū)動,以實現(xiàn)截獲KVM虛擬機的IO。
要實現(xiàn)系統(tǒng)調(diào)用替換,首先通過Linux 內(nèi)核導(dǎo)出函數(shù)kallsyms_lookup_name()獲取系統(tǒng)調(diào)用表,接著替換掉系統(tǒng)調(diào)用表中的目標(biāo)系統(tǒng)調(diào)用函數(shù),最后在替換函數(shù)中執(zhí)行完相關(guān)邏輯,并再調(diào)用原系統(tǒng)調(diào)用函數(shù),保證系統(tǒng)正常運作。
本文所設(shè)計持續(xù)性數(shù)據(jù)保護(hù)系統(tǒng)架構(gòu)如圖3所示。

圖3 持續(xù)性數(shù)據(jù)保護(hù)架構(gòu)
KVM 虛擬機支持多種不同的磁盤格式,如raw、qcow2 以及ceph 格式,不同的磁盤格式有不同的元數(shù)據(jù)用以描述數(shù)據(jù)的儲存方式,在捕獲數(shù)據(jù)IO的同時進(jìn)行備份并不需要這些元數(shù)據(jù)。故針對不同格式的磁盤,需要設(shè)計不同的hook模塊,過濾不同磁盤格式下的元數(shù)據(jù)。
Raw 格式為磁盤原生格式,可以直接掛載在不同的虛擬機中,沒有額外元數(shù)據(jù)需要處理。直接捕獲其IO 數(shù)據(jù)即可。整個過濾驅(qū)動運行流程如圖4所示。

圖4 raw格式磁盤Hook模塊運行流程
如圖4 所示,當(dāng)QEMU 產(chǎn)生了IO 請求時,首先會通過IO 過濾驅(qū)動,由過濾驅(qū)動判斷是否是目標(biāo)磁盤文件,若為目標(biāo)文件,則通過數(shù)據(jù)傳輸模塊將IO 數(shù)據(jù)傳到遠(yuǎn)端數(shù)據(jù)備份服務(wù)器進(jìn)行備份,之后將參數(shù)傳回原系統(tǒng)調(diào)用函數(shù)進(jìn)行正常寫入操作。
對qcow2磁盤進(jìn)行數(shù)據(jù)捕獲操作時,需要對元數(shù)據(jù)進(jìn)行過濾操作,只保存實際數(shù)據(jù)。
qcow2 磁盤開頭是一個固定存放在文件頭的結(jié)構(gòu)體,這個結(jié)構(gòu)體描述了該qcow2文件的一些相關(guān)信息,結(jié)構(gòu)體代碼如下。
typedef struct QCowHeader{
uint32_t magic;
uint32_t version;
uint64_t backing_file_offset;
uint32_t backing_file_size;
uint32_t cluster_bits;
uint64_t size;/*in bytes*/
uint32_t crypt_method;
uint32_t l1_size;
uint64_t l1_table_offset;
uint64_t refcount_table_offset;
uint32_t refcount_table_clusters;
uint32_t nb_snapshots;
uint64_t snapshots_offset;
}QCowHeader;
其中,需要關(guān)注的是l1_size、l1_table_offset以及cluster_bits 這幾項,l1_size是指l1table的大小,l1_table_offset 是l1 表在文件中的偏移,而cluster bits 則是用來計算qcow2 格式的一個cluster的大小,計算方法為1< l1 表和l2 表是一個二級表項的儲存結(jié)構(gòu),其中儲存的是raw 磁盤格式道qocw2 磁盤格式的偏移信息。l1表的大小不固定,隨著qcow2文件增長而增長,其中每個表項長度為8個字節(jié),而l2 表固定為一個cluster 大小,其中每個表項為8個字節(jié),一個qcow2 只能有一個有效的l1table,但是同時擁有多個l2table。l1table的第一項指向qcow2 文件中的第一個l2table 項,而第一個l2table 的第一項所指向的那個cluster,在轉(zhuǎn)換成raw 格式后,其就是raw 格式的第一個cluster。所以,根據(jù)此二級表項,便可將qcow2格式動態(tài)轉(zhuǎn)化為raw 格式數(shù)據(jù),整個qcow2 磁盤數(shù)據(jù)捕獲具體流程如圖5所示。 圖5 qcow2格式磁盤Hook模塊運行流程 模塊加載時,首先會讀取磁盤文件中的元數(shù)據(jù)信息,根據(jù)元數(shù)據(jù)信息解析l1table 和l2table,并等待數(shù)據(jù)下發(fā)。當(dāng)有針對目標(biāo)文件寫IO 到達(dá)時,首先根據(jù)解析出來的數(shù)據(jù)判斷是否是元數(shù)據(jù),若為元數(shù)據(jù),直接下發(fā)IO,并重新解析l1table和l2table,重新解析兩個表是因為如果寫入數(shù)據(jù)是元數(shù)據(jù),則有可能改變l1table 和l2table 內(nèi)容。若非元數(shù)據(jù),則先將數(shù)據(jù)寫入備份文件,之后將IO下發(fā)到目標(biāo)文件。 KVM+ceph 是當(dāng)前云環(huán)境下的常用組合,作為一款分布式文件系統(tǒng),ceph在云環(huán)境中相對于傳統(tǒng)文件系統(tǒng)能夠發(fā)揮出更好的性能。 KVM 虛擬機使用ceph 作為儲存,主要是用到librbd調(diào)用的ceph的IO接口,librbd是ceph基于librados的一個用戶態(tài)接口,當(dāng)我們在KVM中通過QEMU使用ceph文件系統(tǒng)時,QEMU通過librbd.so文件調(diào)用接口進(jìn)行IO,所以其數(shù)據(jù)我們無法通過系統(tǒng)調(diào)用進(jìn)行hook,想要獲取ceph儲存的IO數(shù)據(jù),需要在應(yīng)用層進(jìn)行hook操作。 在應(yīng)用層的hook 通常是指PLT/GOT hook,也就是對程序的got 表進(jìn)行替換。PLT(Problogcedure Linkage Table)和GOT(Global Offset Table)是GCC 中生成shared library 的重要元素。Linux 對外部函數(shù)的引用是采用動態(tài)鏈接的,也就是說,只有在用到某個函數(shù)時,才會具體定位其在內(nèi)存中的位置。 對于正在運行的程序,可以通過修改.got.plt 表將目標(biāo)函數(shù)地址改為hook 函數(shù)的地址,實現(xiàn)對函數(shù)的hook,若程序還未運行,則可通過LD_PRELOAD 環(huán)境變量,直接將目標(biāo)so 文件替換為hook所需的so文件。 針對ceph文件系統(tǒng)的IO函數(shù)Hook具體過程如圖6所示。 圖6 ceph磁盤Hook模塊運行流程 如圖6所示,首先程序會判斷kvm 虛擬機是否啟動,若未啟動,則通過LD_PRELOAD 環(huán)境變量,讓kvm 啟動時自動加載hook 所需的so 文件,程序啟動后,so 文件的代碼會自動替換qemu 中關(guān)于ceph 的IO 函數(shù)。若KVM 虛擬機已啟動,則需要首先調(diào)用程序libc 庫中dlopen 函數(shù),將hook 所需so 文件載入內(nèi)存,之后通過Linux 的proc 文件系統(tǒng)修改進(jìn)程內(nèi)存,將.got.plt表中的目標(biāo)函數(shù)地址修改為hook 函數(shù)地址,實現(xiàn)對數(shù)據(jù)的捕獲。 針對數(shù)據(jù)恢復(fù),本文設(shè)計了兩種恢復(fù)模式。第一種為數(shù)據(jù)卷恢復(fù)模式,即當(dāng)數(shù)據(jù)卷出現(xiàn)損壞或誤操作時,將數(shù)據(jù)恢復(fù)到最初的數(shù)據(jù)卷狀態(tài),此時恢復(fù)模塊會直接讀取備份庫中的數(shù)據(jù)卷快照文件,將數(shù)據(jù)卷恢復(fù)到最初狀態(tài)。第二種則為目標(biāo)點恢復(fù)模式,首先,在IO 數(shù)據(jù)備份時,系統(tǒng)會按照時間順序?qū)O 數(shù)據(jù)進(jìn)行排序,當(dāng)用戶指定一個恢復(fù)的時間點后,恢復(fù)模塊會通過原始磁盤鏡像以及備份庫中所儲存的IO 數(shù)據(jù),按時間順序?qū)Υ疟P進(jìn)行IO 重放,直到恢復(fù)到目標(biāo)時間點為止。由此實現(xiàn)恢復(fù)到任意時間點的目標(biāo)。 本文測試系統(tǒng)由一臺測試服務(wù)器和一臺備份服務(wù)器組成,測試服務(wù)器用于運行KVM 虛擬機,備份服務(wù)器用于保存以及讀取數(shù)據(jù)捕獲模塊所捕獲的數(shù)據(jù)。 實驗首先隨機產(chǎn)生一個數(shù)據(jù)文件,計算文件MD5 碼并進(jìn)行保存,之后在測試服務(wù)器上開啟KVM 虛擬機,分別使用raw、qcow2 以及ceph格式作為測試磁盤,將產(chǎn)生的數(shù)據(jù)文件寫入測試磁盤,然后對磁盤進(jìn)行格式化操作。最后,在使用恢復(fù)模塊將磁盤恢復(fù)到數(shù)據(jù)格式化前,計算出恢復(fù)數(shù)據(jù)文件MD5 碼,若MD5 碼不變,則證明本文所設(shè)計系統(tǒng)能夠正確保護(hù)數(shù)據(jù)。實驗結(jié)果見表1。 表1 實驗結(jié)果 實驗結(jié)果表明,本文提出的持續(xù)性數(shù)據(jù)保護(hù)方法能夠正確地對不同格式磁盤數(shù)據(jù)進(jìn)行保護(hù)。 針對KVM 虛擬機數(shù)據(jù)備份,本文提出了一種KVM 虛擬機數(shù)據(jù)持續(xù)性保護(hù)的設(shè)計以及開發(fā)思路,通過在應(yīng)用層和內(nèi)核層編寫Hook 函數(shù),實現(xiàn)了對KVM虛擬機IO的數(shù)據(jù)捕獲,并通過IO重放的機制,將數(shù)據(jù)恢復(fù)到任意時間點,該設(shè)計具有一定的創(chuàng)新型,為KVM 虛擬機的數(shù)據(jù)保護(hù)提供了一種全新的思路。但目前針對不同的磁盤格式IO 捕獲,仍存在適配性問題,下一步工作將針對此問題做進(jìn)一步研究,以適應(yīng)更多的磁盤格式。
2.3 ceph格式磁盤Hook模塊設(shè)計

2.4 數(shù)據(jù)恢復(fù)模塊設(shè)計
3 實驗

4 結(jié)語