參考鏈接
- Lniux加密框架中的主要數據結構(五)_家有一希的博客-CSDN博客
?crypto_larval
struct crypto_larval {struct crypto_alg alg;struct crypto_alg *adult;struct completion completion;u32 mask;
};
- 結構體名叫 crypto_larval (算法幼蟲)
- internal.h - crypto/internal.h - Linux source code (v5.15.12) - Bootlin
- 數據成員? 細分
- alg:算法幼蟲對應的通用算法說明;
- adult:算法幼蟲對應的算法成蟲,即待注冊或待檢驗的算法;
- completion:算法幼蟲對應的完成量,用于在注冊或檢驗過程中進行線程同步;struct completion - 用于維護“完成”狀態的結構:這是用于維護“完成”狀態的不透明結構。完成當前使用 FIFO 來排隊必須等待的線程“完成”事件。
- mask:算法類型屏蔽字。
- 在加密框架中每種算法都對應一個通用算法說明,需要由算法管理鏈表管理,算法幼蟲是一種特殊的算法,不“成熟”,無法提供算法服務,因此其通用算法說明只是用來表示算法幼蟲的屬性(如算法名,算法類型等),并不提供算法接口。
- 在加密框架中,算法動態注冊和算法正確性檢驗都是由專門的內核線程實現的,與執行算法查找或算法注冊的內核線程之間通過完成量機制實現線程間同步。?
completion
-
?completion.h - include/linux/completion.h - Linux source code (v5.15.12) - Bootlin
/** struct completion - structure used to maintain state for a "completion"** This is the opaque structure used to maintain the state for a "completion".* Completions currently use a FIFO to queue threads that have to wait for* the "completion" event.** See also: complete(), wait_for_completion() (and friends _timeout,* _interruptible, _interruptible_timeout, and _killable), init_completion(),* reinit_completion(), and macros DECLARE_COMPLETION(),* DECLARE_COMPLETION_ONSTACK().*/
struct completion {unsigned int done;struct swait_queue_head wait;
};
crypto_larval_alloc
- api.c - crypto/api.c - Linux source code (v5.15.12) - Bootlin
- crypto_larval_alloc函數輸入參數包括算法名name、算法類型type和算法類型屏蔽字mask,實現根據輸入參數創建同名的算法幼蟲larval的功能。
struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask)
{struct crypto_larval *larval;larval = kzalloc(sizeof(*larval), GFP_KERNEL);if (!larval)return ERR_PTR(-ENOMEM);larval->mask = mask;larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type;larval->alg.cra_priority = -1;larval->alg.cra_destroy = crypto_larval_destroy;strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);init_completion(&larval->completion);return larval;
}
EXPORT_SYMBOL_GPL(crypto_larval_alloc);
- 在crypto_larval_alloc函數中對新創建的算法幼蟲的初始化如下所示
?
在算法幼蟲初始化時,需要注意以下幾點:
- a)算法幼蟲與算法同名;
- b)算法幼蟲的算法類型設置CRYPTO_ALG_LARVAL;
- c)算法幼蟲的算法優先級為-1;
- d)算法幼蟲設置了實例銷毀接口crypto_larval_destroy。
- 將crypto_larval_alloc函數創建的算法幼蟲稱為通用算法幼蟲,實際上就是注冊用算法幼蟲。
- completion.h - include/linux/completion.h - Linux source code (v5.15.12) - Bootlin
- init_completion?
/*** init_completion - Initialize a dynamically allocated completion* @x: pointer to completion structure that is to be initialized** This inline function will initialize a dynamically created completion* structure.*/
static inline void init_completion(struct completion *x)
{x->done = 0;init_swait_queue_head(&x->wait);
}
- init_await_queue_head()
- swait.h - include/linux/swait.h - Linux source code (v5.15.12) - Bootlin
?
?__crypto_register_alg
- algapi.c - crypto/algapi.c - Linux source code (v5.15.12) - Bootlin
?
- 在__crypto_register_alg函數中,再調用crypto_larval_alloc函數創建通用算法幼蟲基礎上,再進行如下設置,設置之后的算法幼蟲稱為檢測用算法幼蟲。?
?與通用算法幼蟲(即注冊用算法幼蟲)相比,檢測用算法幼蟲增加了以下屬性:
- a)檢驗用算法幼蟲設置了對應的算法成蟲;?larval->adult = crypto_mod_get(alg);
- b)檢驗用算法幼蟲設置了對應的算法驅動名;memcpy(larval->alg.cra_driver_name, alg->cra_driver_name,CRYPTO_MAX_ALG_NAME);
- c)檢驗用算法幼蟲繼承了算法成功的算法優先級。larval->alg.cra_priority = alg->cra_priority;
- 沒有修改引用計數嗎?refcount_set(&larval->alg.cra_refcnt, 1);
- 在加密框架中,用是否設置了算法驅動名來區分注冊用算法幼蟲和檢測用算法幼蟲,由內聯函數crypto_is_test_larval實現,如下所示。?
crypto_is_test_larval函數
- api.c - crypto/api.c - Linux source code (v5.15.12) - Bootlin
static inline int crypto_is_test_larval(struct crypto_larval *larval)
{return larval->alg.cra_driver_name[0];
}
crypto_larval_add函數
- api.c - crypto/api.c - Linux source code (v5.15.12) - Bootlin
- crypto_larval_add函數輸入參數包括算法名name、算法類型type和算法類型屏蔽字mask
static struct crypto_alg *crypto_larval_add(const char *name, u32 type,u32 mask)
{struct crypto_alg *alg;struct crypto_larval *larval;larval = crypto_larval_alloc(name, type, mask);if (IS_ERR(larval))return ERR_CAST(larval);refcount_set(&larval->alg.cra_refcnt, 2);down_write(&crypto_alg_sem);alg = __crypto_alg_lookup(name, type, mask);if (!alg) {alg = &larval->alg;list_add(&alg->cra_list, &crypto_alg_list);}up_write(&crypto_alg_sem);if (alg != &larval->alg) {kfree(larval);if (crypto_is_larval(alg))alg = crypto_larval_wait(alg);}return alg;
}
-
處理流程如下所示
- ?如上所示,crypto_larval_add函數并不是簡單調用crypto_larval_alloc函數創建注冊用算法幼蟲larval,在返回前要調用__crypto_alg_lookup函數再次查找是否有符合條件的算法alg,根據查找結果確認返回值。
- 算法幼蟲larval和算法alg在數據結構上的共同點為通用算法說明,因此crypto_larval_add函數的返回值是通用算法說明,而調用者通過算法類型判斷某個通用算法說明是否對應一個算法幼蟲,由內聯函數crypto_is_larval函數實現
crypto_is_larval
- 判斷某個通用算法說明是否對應一個算法幼蟲,由內聯函數crypto_is_larval函數實現
- internal.h - crypto/internal.h - Linux source code (v5.15.12) - Bootlin
static inline int crypto_is_larval(struct crypto_alg *alg)
{return alg->cra_flags & CRYPTO_ALG_LARVAL;
}
3)crypto_larval_wait函數
- crypto_larval_wait函數用于等待算法檢測(即算法注冊)完成,通過完成量實現與算法檢測線程之間的同步,其完成量是帶超時(60s)可中斷的
- api.c - crypto/api.c - Linux source code (v5.15.12) - Bootlin
static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
{struct crypto_larval *larval = (void *)alg;long timeout;timeout = wait_for_completion_killable_timeout(&larval->completion, 60 * HZ);alg = larval->adult;if (timeout < 0)alg = ERR_PTR(-EINTR);else if (!timeout)alg = ERR_PTR(-ETIMEDOUT);else if (!alg)alg = ERR_PTR(-ENOENT);else if (IS_ERR(alg));else if (crypto_is_test_larval(larval) &&!(alg->cra_flags & CRYPTO_ALG_TESTED))alg = ERR_PTR(-EAGAIN);else if (!crypto_mod_get(alg))alg = ERR_PTR(-EAGAIN);crypto_mod_put(&larval->alg);return alg;
}
- 超時中斷,如下所示
timeout = wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ);
- crypto_larval_wait函數只是簡單地等待算法檢測完成,而算法檢測結果還需要通過其他條件進行綜合判斷,包括完成量返回的剩余時間timeout、算法幼蟲關聯的算法成蟲alg(=larval->adult)
- 檢測條件為 :?完成量返回的剩余時間timeout? 和??算法幼蟲關聯的算法成蟲alg?
?具體規則如下:
- i.根據timeout值判斷線程同步結果
- timeout<0說明等待被外部信號中斷,返回EINTR錯誤
- timeout=0說明等待算法注冊超時,返回ETIMEDOUT
-
if (timeout < 0)alg = ERR_PTR(-EINTR);else if (!timeout)alg = ERR_PTR(-ETIMEDOUT);
-
ii.timeout>0說明算法注冊在超時時間內完成,但是注冊完成并不代表注冊成功,還需要進一步判斷
- 例如注冊用算法幼蟲關聯的算法成功alg無效說明算法注冊失敗,返回ENOENT(即沒有這個算法)錯誤;
- 如果算法幼蟲為檢驗用算法幼蟲,但算法未經過檢驗,返回EAGAIN錯誤,允許重新嘗試算法注冊流程,如下所示。
-
if (!alg)alg = ERR_PTR(-ENOENT);else if (crypto_is_test_larval(larval) &&!(alg->cra_flags & CRYPTO_ALG_TESTED))alg = ERR_PTR(-EAGAIN);
- iii.以上條件均不滿足時,說明算法已成功完成注冊,返回注冊好的算法alg。
4)crypto_larval_kill函數
- 算法注冊成功,同時也意味著算法幼蟲使用的終結,注冊線程將調用crypto_larval_kill函數“殺死”算法幼蟲。
- api.c - crypto/api.c - Linux source code (v5.15.12) - Bootlin
void crypto_larval_kill(struct crypto_alg *alg)
{struct crypto_larval *larval = (void *)alg;down_write(&crypto_alg_sem);list_del(&alg->cra_list);up_write(&crypto_alg_sem);complete_all(&larval->completion);crypto_alg_put(alg);
}
EXPORT_SYMBOL_GPL(crypto_larval_kill);
具體操作流程?
- 首先從算法管理鏈表中刪除算法幼蟲,使之變為孤兒;?? ?list_del(&alg->cra_list);
- 然后喚醒在算法幼蟲完成量上等待的所有線程,使之變得無用;complete_all(&larval->completion);
- 最后釋放算法幼蟲的占有權,徹底判處其死刑。crypto_alg_put(alg);
- 內聯函數crypto_alg_put用于釋放算法alg(包括算法幼蟲)的占有權
crypto_alg_put
- internal.h - crypto/internal.h - Linux source code (v5.15.12) - Bootlin
static inline void crypto_alg_put(struct crypto_alg *alg)
{if (refcount_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)alg->cra_destroy(alg);
}
- 釋放算法占有權時,如果算法定義了cra_destroy接口,將調用其進行進一步處理,而在創建算法幼蟲(crypto_larval_alloc函數)時將算法幼蟲的cra_destroy接口設置為crypto_larval_destroy函數。
- crypto_larval_destroy函數將先釋放對算法成蟲adult(如果有)的占用權,最終釋放算法幼蟲占用的內存空間,這樣算法幼蟲形神俱滅,消失的無影無蹤。
???????