LWN: Git中的一個漏洞!
關(guān)注了就能看到更多這么棒的文章哦~
A vulnerability in Git
By Jake Edge
March 10, 2021
DeepL assisted translation
https://lwn.net/Articles/848935/
3 月 9 日,Git(知名的分布式版本控制系統(tǒng))中公開了一個嚴(yán)重的潛在漏洞。漏洞的詳細(xì)描述中有很多限定詞,因此看起來它的適用條件非常嚴(yán)苛,事實(shí)也確實(shí)是這樣。因此它并不是那么令人擔(dān)憂,但這并不絕對。與大多數(shù)漏洞一樣,它是否會被利用取決于軟件的使用方式和運(yùn)行環(huán)境。
在對一個精心制作來利用該漏洞(CVE-2021-213)的倉庫進(jìn)行 clone 時(shí),可能會在本地系統(tǒng)上發(fā)生非法代碼執(zhí)行(code execution on the local system)。前提條件之一是要安裝了某種 Git filter。Filters 允許本地文件系統(tǒng)中的 Git 倉庫和遠(yuǎn)程倉庫中過濾掉一部分文件;"smudge" filter 用在從 repository 中提取 blobs(二進(jìn)制對象)并存儲到當(dāng)前工作目錄中的過程中,而 "clean" filter 則可以在將文件提交到 repository 時(shí)對其進(jìn)行修改。需要使用哪種類型的 filter,取決于打算進(jìn)行什么類型的轉(zhuǎn)換。Git 大文件存儲(LFS)是一個很常用的擴(kuò)展(其中使用了 smudge 和 clean filter),Windows 版本的 Git 默認(rèn)就安裝了 LFS。
使用 filter 時(shí)可以將一些 Git 操作的處理延后,這樣一來那些需要長期運(yùn)行的 filter 動作可以在后臺進(jìn)行。例如,Git LFS 可能需要在通過網(wǎng)絡(luò)來復(fù)制一個大文件從而完成 git checkout 操作。不過,這個延后的動作就改變了 Git 正常處理文件和目錄的順序。這就意味著緩存的信息在被用到時(shí)可能已經(jīng)失效了,這正是漏洞出現(xiàn)的原因。
為了減少調(diào)用 lstat()的次數(shù),Git 維護(hù)了一個 "lstat cache"。如果在文件被 checkout 的過程中發(fā)生了路徑?jīng)_突(path collision,即兩個文件的路徑和文件名都相同),例如兩個名稱中僅有大小寫不同的文件被 checkout 到一個不區(qū)分大小寫的文件系統(tǒng)中,那么這個 cache 就可能是錯誤的。這通常不會導(dǎo)致問題,因?yàn)?checkout 是按照順序進(jìn)行的,所以就算碰上緩存錯誤了,但是此時(shí) cache 實(shí)際上也用不上。
然而,如果 checkout 中某些動作被 filter 延后了,那么就會有風(fēng)險(xiǎn)了。在查詢 cache 時(shí),cache 中的文件的類型可能發(fā)生了變化,如果這種變化是由攻擊者精心構(gòu)造的,那么就會出現(xiàn)惡意攻擊行為了。修復(fù)該漏洞的 patch中是這樣描述的:
但是, checkout 機(jī)制中有一些情況并不總是遵循 index 順序的。具體來說:checkout-index 會按照命令行上(或 stdin)上出現(xiàn)的順序來寫入 path 信息,而 delayed checkout 功能(用在某個需要長時(shí)間運(yùn)行的 filter 進(jìn)程回復(fù) "status=delayed")則會推遲一些內(nèi)容的 checkout 操作,從而導(dǎo)致 checkout 順序變化了。
當(dāng)我們必須不按順序 checkout 某個文件時(shí)并且 lstat() cache 此時(shí)是 invalid 的(由于之前提到的路徑碰撞),那么 checkout_entry() 可能最終用到的就是這個 invalid 的數(shù)據(jù),并[相信] 這個文件名之前的那串路徑都是真實(shí)的目錄,從而被欺騙了。比如目錄部分實(shí)際上是一個普通文件,那么用戶會得到一個錯誤。"fatal: unable to create file 'foo/bar'. Not a directory"。但如果目錄部分被換了一個符號鏈接[symbolic link],那么 checkout 動作實(shí)際上可能最終會跟隨符號鏈接將文件寫在一個錯誤的地方,甚至是在 git repository 之外的位置。delayed checkout 就會受這個影響,它可能會被攻擊者用來制作出有問題的 repository,等人們 clone 時(shí)進(jìn)行寫破壞。
修復(fù)時(shí)人們考慮了幾種方案,比如在進(jìn)行不按順序的 checkout 操作時(shí)禁用 cache,或者對文件名進(jìn)行排序,使其始終是按相同的順序處理的。這兩種方法都會影響性能,而且人們擔(dān)心其他還會有一些情況下也會導(dǎo)致出現(xiàn)類似 delayed checkout 這樣的亂序操作,從而使這個 bug 死灰復(fù)燃。因此最終選擇的解決方案是,每次執(zhí)行刪除目錄操作時(shí),就會對 cache 進(jìn)行 invalidate 操作。
如上所述,符號鏈接在這個過程中起到了幫兇的作用。雖然符號鏈接非常有用,但歷史上它也曾被各種利用來進(jìn)行破壞。在 race condition exploits(例如臨時(shí)文件)中就經(jīng)常利用符號鏈接。并非所有的系統(tǒng)都支持符號鏈接,但是 Unix 衍生系統(tǒng)(Linux、macOS)一般都支持。如今,Windows 管理員也可以創(chuàng)建符號鏈接了。
因此,這幾個不同的功能和特殊情況組合在一起,就導(dǎo)致了一個系統(tǒng)漏洞,此外還需要有一個攻擊者精心制作的 Git repository,并且用戶被欺騙去對其進(jìn)行 clone 操作。哪怕是對 Windows 系統(tǒng)這種既使用 Git LFS 而且文件系統(tǒng)也不區(qū)分大小寫的系統(tǒng),利用這個漏洞的攻擊也并沒有怎么見到過,也許可能根本不存在。這看起來是通過代碼審查或測試發(fā)現(xiàn)的問題,隨后被報(bào)告出來并并迅速修復(fù)了,甚至都來不及起一個好聽的名字、設(shè)計(jì)個 logo、或者建個專門的網(wǎng)站。如果真有系統(tǒng)被利用這個漏洞攻破了,那么很可能是因?yàn)檫@些攻擊非常具有針對性,并且還沒有被發(fā)現(xiàn)。
雖然 Linux 原生文件系統(tǒng)通常都會區(qū)分大小寫,但事實(shí)上可以被配置為忽略大小寫。不僅如此,Linux 還可能在使用 Windows 和 macOS 的那些忽略大小寫的文件系統(tǒng)格式。此外,fix patch 中提供的測試程序還揭示了另一種會導(dǎo)致問題的方式,那就是利用 Unicode normalization。測試程序使用了 "?" 的兩種不同的 Unicode 表示形式(U+0061 U+0308,"\141\314\210",和 U+00e4,"\303\244"),并確保文件不會被寫到錯誤的位置。因此,Linux 系統(tǒng)雖然受該 bug 影響的可能性很小,但也并不可以高枕無憂的。
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~
