<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          LWN:LLVM CFI 的新實現(xiàn)方案!

          共 2206字,需瀏覽 5分鐘

           ·

          2022-06-30 18:49

          關注了就能看到更多這么棒的文章哦~

          A new LLVM CFI implementation

          By Jonathan Corbet
          June 17, 2022
          DeepL assisted translation
          https://lwn.net/Articles/898040/

          內核中有些功能比起其他部分能存活得更久一些。在 5.13 版內核中加入了對用 LLVM 編譯的內核的 forward-edge control-flow integrity(CFI)的完整性檢查的支持,但現(xiàn)在已經(jīng)有一個替代品出現(xiàn)了。CFI
          將會被保留下來,但新的實現(xiàn)跟它有很多明顯差異,而且在許多方面似乎更好。

          內核廣泛使用了間接函數(shù)調用(indirect function calls);它們是內核里內部對象模型(internal object model)的核心。每一個這種調用,都是攻擊者的一個潛在攻擊點;如果這個調用的目標地址可以以某種方式被修改為攻擊者所選擇的地址的話,游戲通常就結束了(我們已經(jīng)喪失了安全性)。forward-edge CFI 通過確保每個間接函數(shù)調用都將控制權發(fā)送到實際打算作為該調用目標的代碼位置,來挫敗這種攻擊方式。具體來說,間接函數(shù)調用應該只能指向一個已知的函數(shù)入口位置(function entry point),并且函數(shù)的原型(prototype)應該與調用位置所期望的類型相匹配。

          在 5.13 中合并的 CFI 實現(xiàn)是通過創(chuàng)建 "jump tables" 來實現(xiàn)的,這個表中包含了內核里間接函數(shù)調用的所有合法目標;針對每一類函數(shù)原型,都有一個跳轉表。實際的間接調用就會被替換為跳轉表的查詢操作,以確保預期目標是符合要求的;目標應該是要在與預期函數(shù)原型相對應的跳轉表中找到的。如果該檢查失敗了,就會導致內核 panic。關于這個機制如何工作的更詳細描述,請看 LWN 之前的文章。

          CFI 這么實現(xiàn)了之后可以達到目標,但它也有一些缺點。創(chuàng)建跳轉表就需要查看完整的內核二進制文件;在實踐中就意味著需要在構建內核的時候使用 link-time optimization,這是一個很耗時、并且有時候有問題的工作。用跳轉表項來代替函數(shù)指針變量也意味著這些變量就不能跟相應函數(shù)的地址來進行比較了,而這是內核代碼中有時候確實需要做的動作。如果有一個不存在這類問題的 CFI 實現(xiàn),那就更好了。

          Sami Tolvanen 的這組 patch set 似乎就達到了這個目的。它依賴于一個新的 Clang 編譯器選項(-fsanitize=kcfi),這個選項目前還沒有進入 LLVM mainline。這種 CFI 機制 "旨在用于底層代碼,如操作系統(tǒng)內核上",它就避免了上述問題,但也付出了一些代價,尤其它不能用在那種 execute-only 的內存區(qū)域上(因為它必須要能進行 read 訪問)。

          在用 -fsanitize=kcfi 編譯代碼時,每個函數(shù)的 entry point 前面都有一個代表該函數(shù)原型的 32 位值。這個值是由函數(shù)及其參數(shù)的 C++ 拼寫名稱(mangled name)計算出來的哈希值(部分)。在 x86 系統(tǒng)中,這個哈希值直接放到了一個簡單的 MOV 指令中,并用 INT3 指令包圍起來;這是為了防止哈希值本身被攻擊者所利用。當進行間接函數(shù)調用時,在進行真正的函數(shù)調用之前,會先執(zhí)行額外的代碼來獲取和檢查這個哈希值;如果與預期的不一致就會產生一個 trap(在內核里就是 OOPS)。對哈希值的檢查工作就解釋了為什么不支持 execute-only 內存:因為必須要能從可執(zhí)行代碼中讀取到哈希值。

          在大多數(shù)情況下,這種機制可以在不需要對內核代碼本身做太多改變的情況下就能起效果。至少,比起之前 CFI 實現(xiàn)的那些必須改動來說沒有增加其他的了。然而,用匯編編寫的函數(shù)有些問題,它需要通過其他方式生成這個必需的數(shù)值。為每個間接調用的匯編函數(shù)都生成一個哈希值可能是一項令人厭煩的任務;幸運的是,編譯器提供了一些幫助。每當它看到(在 C 代碼中)一個函數(shù)的地址被使用時(如這個例子):

          static const struct v4l2_file_operations mcam_v4l_fops = {
          .open = mcam_v4l_open, /* ... */};

          它就會生成一個相應的符號,并將其定義為最終得到的哈希值;在此例中,這個符號就會是 __kcfi_typeid_mcam_v4l_open。存在了這些符號,就意味著匯編函數(shù)的前面的那個數(shù)值就可以通過對已經(jīng)用于定義這些函數(shù)的宏進行一些調整而自動生成了。

          這組 patch 目前處于第三版,似乎所有的實質性問題都已經(jīng)解決。換句話說,它看起來已經(jīng)準備好被并入 mainline 了。只剩下一個障礙需要克服:在 LLVM Clang 編譯器真正支持這個功能之前,內核開發(fā)者不會愿意合并這個功能。假設 Clang 不久之后就能支持這個功能的話,那么在內核應該很快就會獲得 arm64 和 x86 架構的升級版 CFI 實現(xiàn)了。

          全文完
          LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。

          歡迎分享、轉載及基于現(xiàn)有協(xié)議再創(chuàng)作~

          長按下面二維碼關注,關注 LWN 深度文章以及開源社區(qū)的各種新近言論~



          瀏覽 20
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天久久夜夜一起射 | 天天看天天干天天操 | 日屄影院 | 免费黄色视频日本 | 亚洲精品国产精品乱码不卡√香蕉 亚洲日韩一区二区三区四区丨高清 |