陳 劍
(浙江訊飛智能科技有限公司 浙江 杭州 311202)
在Linux系統(tǒng)的安全啟動中,通常會使用用戶密鑰來確保內(nèi)核和Initrd文件的完整性和安全性。對于內(nèi)核鏡像,有許多方法可以進(jìn)行簽名驗證,但對于單獨的Initrd文件進(jìn)行簽名驗證的方法卻比較少見。這是因為Initrd文件通常被認(rèn)為是內(nèi)核鏡像的一部分,因此它的安全性往往被忽略。然而在一些場景下,需要對單獨的Initrd鏡像進(jìn)行簽名驗證,這就需要使用一些技術(shù)和工具來實現(xiàn)[1]。Grub是一款廣泛使用的內(nèi)核引導(dǎo)工具。歷經(jīng)多年發(fā)展,Grub已經(jīng)成為一個功能強(qiáng)大、穩(wěn)定可靠的多操作系統(tǒng)引導(dǎo)工具。
本文的方案是創(chuàng)建一個grub.efi的可執(zhí)行文件,其中包含用戶公鑰,以及所需的模塊和基本配置,在執(zhí)行時將加載已簽名的grub.cfg配置文件,該配置文件將加載已簽名的Initrd和內(nèi)核文件。Grub的簽名驗證機(jī)制是基于 GPG(GNU Privacy Guard)的數(shù)字簽名驗證。
Linux內(nèi)核通過配置能掛載一個早期根文件系統(tǒng)來實現(xiàn)系統(tǒng)初始化,這種方法叫做初始RAM盤(Initrd)。通過這個早期根文件系統(tǒng),來引導(dǎo)存儲到其他分區(qū)的根文件系統(tǒng),它是現(xiàn)代操作系統(tǒng)加載時必不可少的文件之一。
操作系統(tǒng)加載器是計算機(jī)啟動時運(yùn)行的第一個程序,它負(fù)責(zé)加載內(nèi)核軟件并將控制權(quán)轉(zhuǎn)交給操作系統(tǒng)內(nèi)核。在早年P(guān)C領(lǐng)域尚不成熟時,各種各樣的操作系統(tǒng)紛繁復(fù)雜,Grub這樣一款小巧強(qiáng)大的多系統(tǒng)引導(dǎo)工具應(yīng)運(yùn)而生,它最初于1995年由Erich Boleyn創(chuàng)建,它可以加載常見的各種開源操作系統(tǒng),現(xiàn)在是GNU計劃的一部分,由Grub開發(fā)團(tuán)隊維護(hù)[2]。
Grub到今天已經(jīng)成長為一個非常強(qiáng)大和靈活的工具,具有許多好的特性。例如:(1)支持模塊化。它能夠?qū)⒃S多功能放在動態(tài)加載的模塊中,常見的有命令模塊(command.lst)、加密模塊(crypto.lst)、文件系統(tǒng)模塊(crypto.lst)等,這種設(shè)計能夠使核心映像文件更小,以更靈活的方式進(jìn)行構(gòu)建。本文的簽名驗證將使用Grub提供的verify模塊。(2)支持友好可讀的配置文件。該配置文件可作為預(yù)設(shè)命令,也支持將配置文件嵌入到Grub映像中。這能夠使得對Grub的開發(fā)更靈活高效。(3)提供靈活的命令接口。Grub的命令與Bash命令行非常相似,可根據(jù)上下文使用TAB完成命令、設(shè)備、分區(qū)和目錄中的文件,對用戶更友好。本文的介紹基于grub2.06。
內(nèi)核在進(jìn)行初始化時,進(jìn)入用戶空間環(huán)境之前系統(tǒng)需要提供一個文件系統(tǒng)。為此,內(nèi)核需要知道文件系統(tǒng)的存儲位置以及該設(shè)備的驅(qū)動程序。當(dāng)設(shè)備驅(qū)動程序作為組件包含在內(nèi)核可執(zhí)行文件中時,可能導(dǎo)致映像文件過大而無法在內(nèi)存有限的計算機(jī)上啟動,可能導(dǎo)致設(shè)備探測不存在或硬件沖突以至于系統(tǒng)崩潰或其他問題[3]。為了避免將文件系統(tǒng)直接編碼到內(nèi)核文件中所出現(xiàn)的這些問題,Initrd(initial RAM disk)機(jī)制得以產(chǎn)生,它是一個臨時的根文件系統(tǒng),現(xiàn)在被稱為早期用戶空間。這個根文件系統(tǒng)能夠進(jìn)行硬件檢測、模塊加載和設(shè)備探測,這些功能是加載真正的根文件系統(tǒng)前所必需的,如圖1所示。
Initrd作為內(nèi)核啟動初始化時的臨時根文件系統(tǒng),很可能成為攻擊者進(jìn)行惡意活動的目標(biāo)。若沒有對Initrd進(jìn)行正確的簽名驗證,使之被篡改或惡意替換,攻擊者可能會在引導(dǎo)過程中注入惡意代碼或獲取系統(tǒng)的敏感信息等,從而對系統(tǒng)進(jìn)行攻擊或進(jìn)行其他惡意行為,系統(tǒng)安全性將無法得到保障。加載簽名后的Initrd,確保了它的來源和完整性,如果簽名驗證失敗,系統(tǒng)將會拒絕啟動,并給出錯誤提示,從而保護(hù)系統(tǒng)免受惡意軟件或黑客攻擊,提高系統(tǒng)的安全性和可靠性[4]。
Grub端的環(huán)境搭建及配置如圖2所示。
圖2 Grub端的環(huán)境搭建及配置
對Grub源碼包進(jìn)行編譯,以取得Grub開發(fā)環(huán)境,如圖3所示。
圖3 Grub源碼包的編譯
(1)運(yùn)行./bootstrap。該腳本文件包含一些用于構(gòu)建Grub引導(dǎo)程序的腳本和配置文件,運(yùn)行后將生成configure、configure.ac等配置文件。
(2)運(yùn)行./configure。該腳本文件根據(jù)當(dāng)前系統(tǒng)的環(huán)境和用戶的配置選項來生成 Makefile。configure 腳本會檢查系統(tǒng)環(huán)境,包括操作系統(tǒng)類型、處理器架構(gòu)、編譯器等,并設(shè)置一些環(huán)境變量。它也能夠讀取用戶提供的選項,例如安裝路徑、編譯選項等,根據(jù)這些選項生成Makefile。其中with-platform需要被顯示指定為efi,該選項用于指定要構(gòu)建的平臺的類型,以便在編譯過程中生成適當(dāng)?shù)拇a。這是因為Grub可以在不同平臺上運(yùn)行,并且不同的平臺可能需要不同的代碼來支持它們的硬件、固件和操作系統(tǒng)。target需要被顯示指定為x86_64,該選項用于指定主機(jī)平臺。
(3)運(yùn)行make進(jìn)行編譯。編譯成功后會生成Grub-mkimage、Grub-install等可執(zhí)行文件。
如上文所述,Grub支持友好可讀的配置文件。配置文件從存放位置看有兩種:(1)嵌入式配置文件。在編譯Grub映像時該配置文件將集成到映像內(nèi)部,在映像得到運(yùn)行時,該配置文件的命令將被順序執(zhí)行。一般該文件會配置設(shè)備根、用戶口令、環(huán)境變量等。這種方式的配置文件可以在進(jìn)入正常模式之前被預(yù)先加載,這樣能夠在外部配置文件無法找到的情況下,也能夠確保應(yīng)用程序的正常運(yùn)行,可以避免配置文件被意外刪除或者被惡意篡改,從而提高核心映像的安全性和可靠性。(2)外部配置文件。外部配置文件一般存放在/boot/grub/grub.cfg或/boot/grub/menu.lst(取決于GRUB版本和Linux發(fā)行版),并由root用戶編輯。一般情況下,該配置文件是由grub-mkconfig自動生成的,不需要開發(fā)人員修改。
外部配置文件一般包括指定一些環(huán)境變量、包含必要的模塊、給出圖形菜單等功能[5]。
本文的嵌入式配置文件如圖4所示。首先指定root變量。環(huán)境變量可以用于控制啟動過程中各種配置參數(shù)的值,Grub有三個核心變量,分別是:cmdpath、prefix、root,核心變量不依賴于任何可加載模塊。Root變量用于指定根文件系統(tǒng)所在的設(shè)備或者分區(qū)。Search.fs_uuid表示找出第一個設(shè)備id為d9002a0f-1c87-4e61-9fff-a4d5d19ef880并將其賦值給root變量。Check_signatures變量用于控制 GRUB 是否對加載的文件強(qiáng)制執(zhí)行數(shù)字簽名驗證。Grub僅支持gpg方式的簽名驗證,使用分離式簽名,簽名文件在同級目錄下。當(dāng)該變量被設(shè)置為enforce時,在Grub下加載的所有文件將被默認(rèn)檢查簽名文件。一般在Grub下要加載的文件有config文件、kernels文件及Initrd文件等。Export用于導(dǎo)出環(huán)境變量,以使其對于使用"configfile"命令載入的配置文件可見。Configurefile用于指出外部配置文件的位置。本文將其放在/boot/grub/grub.cfg.t。(hd0,gpt2)表示第一個硬盤的第二個gpt分區(qū)表,即為文件系統(tǒng)根目錄。若執(zhí)行出錯或未找到外部配置文件,將打印報錯信息并重啟。
圖4 嵌入式配置文件
本文的外部配置文件編寫如圖5所示。外部配置文件只需要完成系統(tǒng)啟動功能即可。配置文件中的腳本語句可在Shell命令行中執(zhí)行。在Grub中啟動操作系統(tǒng)時,需要指定內(nèi)核文件、根設(shè)備以及Initrd文件。命令linux用于從文件加載內(nèi)核,同時需要給出root根設(shè)備的參數(shù),本文使用UUID的方式獲取到根設(shè)備。在執(zhí)行l(wèi)inux命令后用Initrd命令將Initrd文件加載,Initrd命令只能在linux命令后使用。在準(zhǔn)備好相應(yīng)的參數(shù)后,即可執(zhí)行boot命令啟動操作系統(tǒng)。
圖5 外部配置文件的編寫
Grub2僅支持gpg方式的簽名驗證。在編譯生成grub.efi映像時,公鑰文件可作為編譯選項,這樣可將公鑰嵌入在映像內(nèi)部,在映像運(yùn)行被運(yùn)行后,當(dāng)需要進(jìn)行簽名驗證時,該被嵌入的公鑰將被隱式引用。
GPG是一款開源密碼學(xué)軟件,發(fā)展至今已經(jīng)較為完善,應(yīng)用廣泛,它是基于 PGP(pretty good privacy)機(jī)制的加密及簽名軟件,可以極大地保證網(wǎng)絡(luò)用戶傳輸及使用數(shù)據(jù)的安全性。
在操作系統(tǒng)進(jìn)行引導(dǎo)時,被加載的文件有Initrd、linux內(nèi)核及外部配置文件,這三個文件都需要經(jīng)過正確的簽名驗證。步驟如下:
(1)生成GPG公私鑰對。如圖6所示。
圖6 GPG公私鑰對
--gen-key用于產(chǎn)生公私鑰對,成功產(chǎn)生后將得到公鑰id,公私鑰文件存儲在本地密鑰環(huán)中,使用時將自動調(diào)用。
(2)對文件進(jìn)行簽名
如圖7所示,編寫腳本文件,定義存儲公鑰id的變量,使用GPG的—detach-sign選項對文件進(jìn)行簽名。簽名成功后將在同級目錄生成*.sig簽名文件。圖中的腳本語句對grub.cfg.test進(jìn)行的簽名操作,內(nèi)核文件vmlinuz和Initrd文件同理。對這些文件簽名后的目錄如圖8所示。
圖7 腳本文件
圖8 文件簽名后的目錄
將Initrd.img-5.15.0-60-generic.sig與vmlinuz-5.15.0-60-generic.sig放至/boot目錄下(與Initrd和vmlinuz同級),將grub.cfg.test.sig放至/boot/efi目錄下(與grub.cfg.test同級),簽名文件環(huán)境即配置完成。如果在同級目錄下沒有相應(yīng)的簽名文件,將會加載失敗,即無法通過簽名驗證,無法成功地進(jìn)行引導(dǎo)。
Grub-mkimage用于生成Grub啟動映像文件,該命令支持多種不同的選項和參數(shù),可以根據(jù)不同的需求生成不同的啟動映像文件,用戶可以選擇在啟動映像中包含支持特定文件系統(tǒng)的模塊,或者選擇在啟動映像中包含特定的內(nèi)核參數(shù)來生成最合適的Grub可執(zhí)行映像。
簽名驗證的公鑰嵌入在映像文件內(nèi)部,在進(jìn)行簽名驗證時將隱式讀取該公鑰值。在編譯映像文件時由編譯選項指定公鑰文件。編譯選項中指定的公鑰文件首先需要由公鑰id導(dǎo)出生成公鑰文件。如圖9所示。
圖9 公鑰id導(dǎo)出生成公鑰文件
使用Grub-mkimage編譯Grub映像時,公鑰文件由-k指定。-c選項用于執(zhí)行嵌入式配置文件,上文已做過介紹。-p選項用于指定prefix環(huán)境變量。-d選項用于指定映像模塊所在的目錄。-O用于指定目標(biāo)編譯平臺。需要包含的模塊用MODULES變量進(jìn)行定義,該腳本包含了一些必要的模塊,例如分區(qū)模塊(part_gpt)、文件系統(tǒng)模塊(fat、ext2)、加密模塊(gcry_sha512、gcry_rsa)等。正確執(zhí)行該腳本后,即可得到grub.efi映像程序,如圖10所示。
圖10 grub.efi映像程序
在得到grub.efi可執(zhí)行映像程序后,將其放在/boot/efi/grub.efi處(gpt1分區(qū)),即可在OVMF固件shell下運(yùn)行。若配置文件、簽名文件等都正確配置,運(yùn)行g(shù)rub.efi后,將正確加載配置文件中指定的內(nèi)核,如圖11所示。
圖11 正確加載的配置文件
若某一文件的簽名文件不存在或簽名錯誤,則無法進(jìn)入系統(tǒng),并打印報錯log,如圖12所示。
圖12 報錯的log
本文闡述了在Grub環(huán)境下對Initrd做簽名驗證的方案及其實現(xiàn)細(xì)節(jié)。相比于常見的將Initrd編碼進(jìn)內(nèi)核并進(jìn)行簽名驗證的方式,本文提出了對單獨的Initrd做簽名驗證的方法和實現(xiàn)細(xì)節(jié)?,F(xiàn)代操作系統(tǒng)一般將Initrd單獨安排,該方案使操作系統(tǒng)加載時更加安全可靠。