(取消)補丁回撥

Livepatch (取消)補丁回撥為 livepatch 模組提供了一種機制,以便在核心物件被(取消)打補丁時執行回撥函式。 它們可以被認為是一個 強大的功能擴充套件了 livepatching 的能力,包括

  • 安全更新全域性資料

  • “補丁”到 init 和 probe 函式

  • 修補其他無法修補的程式碼(即彙編)

在大多數情況下,(取消)補丁回撥需要與記憶體屏障和核心同步原語(如互斥鎖/自旋鎖),甚至 stop_machine() 結合使用,以避免併發問題。

1. 動機

回撥與現有的核心工具不同

  • 停用和重新啟用補丁時,模組 init/exit 程式碼不會執行。

  • 模組通知器無法阻止要打補丁的模組載入。

回撥是 klp_object 結構的一部分,它們的實現特定於該 klp_object。其他 livepatch 物件可能會也可能不會被打補丁,這與目標 klp_object 的當前狀態無關。

2. 回撥型別

可以為以下 livepatch 操作註冊回撥

  • 預補丁 (Pre-patch)
    • 在 klp_object 打補丁之前

  • 後補丁 (Post-patch)
    • 在 klp_object 打補丁之後,並且在所有任務中都處於活動狀態

  • 預取消補丁 (Pre-unpatch)
    • 在 klp_object 取消補丁之前(即,補丁程式碼處於活動狀態),用於清理後補丁回撥資源

  • 後取消補丁 (Post-unpatch)
    • 在 klp_object 打補丁之後,所有程式碼都已恢復,並且沒有任務執行補丁程式碼,用於清理預補丁回撥資源

3. 工作原理

每個回撥都是可選的,省略一個並不妨礙指定任何其他回撥。但是,livepatching 核心以對稱方式執行處理程式:預補丁回撥具有後取消補丁 counterpart,而後補丁回撥具有預取消補丁 counterpart。僅當其對應的補丁回撥已執行時,才會執行取消補丁回撥。典型的用例是將獲取和配置資源的補丁處理程式與拆卸和釋放這些相同資源的取消補丁處理程式配對。

僅當其宿主 klp_object 已載入時,才會執行回撥。對於核心中的 vmlinux 目標,這意味著當啟用/停用 livepatch 時,回撥將始終執行。對於補丁目標核心模組,僅當目標模組已載入時,才會執行回撥。當模組目標被(取消)載入時,僅當 livepatch 模組已啟用時,才會執行其回撥。

預補丁回撥(如果指定)應返回狀態程式碼(0 表示成功,-ERRNO 表示錯誤)。錯誤狀態程式碼向 livepatching 核心指示,當前 klp_object 的補丁不安全,並停止當前的補丁請求。(如果未提供預補丁回撥,則假定轉換是安全的。)如果預補丁回撥返回失敗,則核心的模組載入器將

  • 如果 livepatch 在目的碼之後載入,則拒絕載入 livepatch。

  • 如果 livepatch 已成功載入,則拒絕載入模組。

如果物件由於預補丁回撥失敗或任何其他原因而未能打補丁,則不會為給定的 klp_object 執行任何後補丁、預取消補丁或後取消補丁回撥。

如果補丁轉換被反轉,則不會執行任何預取消補丁處理程式(這遵循前面提到的對稱性 - 只有在其相應的後補丁回撥已執行時,才會發生預取消補丁回撥)。

如果物件已成功打補丁,但由於某種原因(例如,如果另一個物件未能打補丁)而從未啟動補丁轉換,則只會呼叫後取消補丁回撥。

4. 用例

演示回撥 API 的示例 livepatch 模組可以在 samples/livepatch/ 目錄中找到。這些示例已被修改用於 kselftests,可以在 lib/livepatch 目錄中找到。

全域性資料更新

預補丁回撥可用於更新全域性變數。例如,commit 75ff39ccc1bd (“tcp: make challenge acks less predictable”) 更改了全域性 sysctl,以及修補了 tcp_send_challenge_ack() 函式。

在這種情況下,如果我們非常偏執,那麼在補丁完成後使用後補丁回撥修補資料可能更有意義,以便首先可以將 tcp_send_challenge_ack() 更改為使用 READ_ONCE 讀取 sysctl_tcp_challenge_ack_limit。

支援 __init 和 probe 函式補丁

雖然 __init 和 probe 函式不能直接進行 livepatching,但可以透過預/後補丁回撥實現類似的更新。

The commit 48900cb6af42 (“virtio-net: drop NETIF_F_FRAGLIST”) 更改了 virtnet_probe() 初始化其驅動程式的 net_device 特性的方式。 預/後補丁回撥可以迭代所有此類裝置,對其 hw_features 值進行類似的更改。(可能需要相應地更新該值的客戶端函式。)