系統狀態變更

有些使用者非常不願意重啟系統。 這就需要提供更多的 livepatch 並保持它們之間的一些相容性。

使用累積 livepatch 可以更容易地維護更多的 livepatch。 每個新的 livepatch 完全替換任何舊的 livepatch。 它可以保留、新增甚至刪除修復。 並且由於原子替換功能,通常可以安全地將任何版本的 livepatch 替換為任何其他版本。

問題可能出在影子變數和回撥上。 它們可能會改變系統行為或狀態,使其不再安全地返回並使用舊的 livepatch 或原始核心程式碼。 此外,任何新的 livepatch 都必須能夠檢測到已經安裝的 livepatch 所做的更改。

這就是 livepatch 系統狀態跟蹤發揮作用的地方。 它允許

  • 儲存操作和恢復系統狀態所需的資料

  • 使用更改 ID 和版本定義 livepatch 之間的相容性

1. Livepatch 系統狀態 API

系統狀態可能會被多個 livepatch 回撥或新使用的程式碼修改。 此外,必須能夠找到已安裝的 livepatch 所做的更改。

每個修改後的狀態都由 struct klp_state 描述,請參閱 include/linux/livepatch.h。

每個 livepatch 定義一個 struct klp_states 陣列。 它們提到 livepatch 修改的所有狀態。

livepatch 作者必須為每個 struct klp_state 定義以下兩個欄位

  • id

    • 用於標識受影響的系統狀態的非零數字。

  • version

    • 描述給定 livepatch 支援的系統狀態更改變體的數字。

可以使用以下兩個函式操作狀態

2. Livepatch 相容性

系統狀態版本用於防止載入不相容的 livepatch。 檢查在啟用 livepatch 時完成。 規則是

  • 允許任何全新的系統狀態修改。

  • 對於已修改的系統狀態,允許使用相同或更高版本的系統狀態修改。

  • 累積 livepatch 必須處理來自已安裝的 livepatch 的所有系統狀態修改。

  • 允許非累積 livepatch 觸及已修改的系統狀態。

3. 支援的場景

Livepatch 有其生命週期,系統狀態變更也是如此。 每個相容的 livepatch 都必須支援以下場景

  • 當啟用 livepatch 並且該狀態尚未被正在被替換的 livepatch 修改時,修改系統狀態。

  • 接管或更新系統狀態修改,如果它已經被正在被替換的 livepatch 完成。

  • 停用 livepatch 時,恢復原始狀態。

  • 還原轉換時,恢復先前的狀態。 可能是原始系統狀態或正在被替換的 livepatch 所做的狀態修改。

  • 當發生錯誤且無法啟用 livepatch 時,刪除任何已做的更改。

4. 預期用法

系統狀態通常由 livepatch 回撥修改。 每個回撥的預期角色如下

pre_patch()

  • 必要時分配 *state->data*。 分配可能會失敗,並且 *pre_patch()* 是唯一可以停止載入 livepatch 的回撥。 如果資料已由先前安裝的 livepatch 提供,則不需要分配。

  • 在轉換完成之前,執行新程式碼所需的任何其他準備操作。 例如,初始化 *state->data*。

    系統狀態本身通常在 *post_patch()* 中修改,此時整個系統都能夠處理它。

  • 發生錯誤時清理自己的爛攤子。 這可以透過自定義程式碼或顯式呼叫 *post_unpatch()* 來完成。

post_patch()

  • 當它們相容時,從先前的 livepatch 複製 *state->data*。

  • 進行實際的系統狀態修改。 最終允許新程式碼使用它。

  • 確保 *state->data* 具有所有必要的資訊。

  • 當不再需要時,從替換的 livepatch 中釋放 *state->data*。

pre_unpatch()

  • 防止 livepatch 新增的程式碼依賴於系統狀態更改。

  • 還原系統狀態修改。

post_unpatch()

  • 透過檢查 *klp_get_prev_state()* 區分轉換反轉和 livepatch 停用。

  • 在轉換反轉的情況下,恢復先前的系統狀態。 這可能意味著什麼都不做。

  • 刪除任何不再需要的設定或資料。

注意

*pre_unpatch()* 通常執行與 *post_patch()* 對稱的操作。 唯一的區別是它僅在停用 livepatch 時被呼叫。 因此,它不需要關心任何先前安裝的 livepatch。

*post_unpatch()* 通常執行與 *pre_patch()* 對稱的操作。 它也可能在轉換反轉期間被呼叫。 因此,它必須處理先前安裝的 livepatch 的狀態。