When EVP_MD_CTX_copy is used, the session is shared among ctxs.
Ensure that the session is released when it is not used.
Signed-off-by: Wenkai Lin <linwenkai6(a)hisilicon.com>
---
src/uadk_digest.c | 184 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 163 insertions(+), 21 deletions(-)
diff --git a/src/uadk_digest.c b/src/uadk_digest.c
index b75c408..b7b9533 100644
--- a/src/uadk_digest.c
+++ b/src/uadk_digest.c
@@ -148,6 +148,78 @@ static EVP_MD *uadk_sha256;
static EVP_MD *uadk_sha384;
static EVP_MD *uadk_sha512;
+struct ctx_info {
+ /* Use md_ctx as the key */
+ EVP_MD_CTX *md_ctx;
+ /* Multiple ctxs may share the same session and data */
+ handle_t sess;
+ unsigned char *data;
+ struct ctx_info *next;
+};
+
+/* Global table to record ctx and its session */
+static struct ctx_info *digest_ctx_info;
+/* Lock for global ctx_info table */
+static pthread_mutex_t digest_ctx_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void find_ctx_info(EVP_MD_CTX *ctx, struct ctx_info **node)
+{
+ struct ctx_info *pnext = digest_ctx_info;
+
+ while (pnext) {
+ if (pnext->md_ctx == ctx) {
+ *node = pnext;
+ return;
+ }
+ pnext = pnext->next;
+ }
+}
+
+static void del_ctx_info(struct ctx_info *node)
+{
+ struct ctx_info *pnext = digest_ctx_info;
+
+ if (pnext == node) {
+ digest_ctx_info = pnext->next;
+ return;
+ }
+
+ while (pnext) {
+ if (pnext->next == node) {
+ pnext->next = pnext->next->next;
+ return;
+ }
+ pnext = pnext->next;
+ }
+}
+
+static void add_ctx_info(struct ctx_info *node)
+{
+ struct ctx_info *pnext = digest_ctx_info;
+
+ if (!pnext) {
+ digest_ctx_info = node;
+ node->next = NULL;
+ } else {
+ node->next = digest_ctx_info;
+ digest_ctx_info = node;
+ }
+}
+
+static bool is_ctx_sess_shared(struct ctx_info *node)
+{
+ struct ctx_info *pnext = digest_ctx_info;
+
+ while (pnext) {
+ if ((pnext != node) && (pnext->sess == node->sess))
+ return true;
+
+ pnext = pnext->next;
+ }
+
+ return false;
+}
+
static const EVP_MD *uadk_e_digests_soft_md(uint32_t e_nid)
{
const EVP_MD *digest_md = NULL;
@@ -491,6 +563,7 @@ static int uadk_e_init_digest(void)
goto err_unlock;
g_digest_engine.pid = getpid();
+ digest_ctx_info = NULL;
pthread_spin_unlock(&g_digest_engine.lock);
free(dev);
}
@@ -515,7 +588,7 @@ static void digest_priv_ctx_setup(struct digest_priv_ctx *priv,
priv->req.out_bytes = out_len;
}
-static void digest_priv_ctx_cleanup(struct digest_priv_ctx *priv)
+static void digest_priv_ctx_reset(struct digest_priv_ctx *priv)
{
/* Ensure that private variable values are initialized */
priv->state = SEC_DIGEST_INIT;
@@ -524,29 +597,52 @@ static void digest_priv_ctx_cleanup(struct digest_priv_ctx *priv)
priv->switch_flag = 0;
}
+static int alloc_ctx_info(EVP_MD_CTX *ctx)
+{
+ struct digest_priv_ctx *priv =
+ (struct digest_priv_ctx *) EVP_MD_CTX_md_data(ctx);
+ struct ctx_info *node = NULL;
+
+ pthread_mutex_lock(&digest_ctx_mutex);
+ find_ctx_info(ctx, &node);
+ if (node == NULL) {
+ node = malloc(sizeof(*node));
+ if (node == NULL) {
+ pthread_mutex_unlock(&digest_ctx_mutex);
+ return 0;
+ }
+ node->md_ctx = ctx;
+ add_ctx_info(node);
+ }
+ node->sess = priv->sess;
+ node->data = priv->data;
+ pthread_mutex_unlock(&digest_ctx_mutex);
+
+ return 1;
+}
+
static int uadk_e_digest_init(EVP_MD_CTX *ctx)
{
struct digest_priv_ctx *priv =
(struct digest_priv_ctx *) EVP_MD_CTX_md_data(ctx);
__u32 digest_counts = ARRAY_SIZE(digest_info_table);
- int nid = EVP_MD_nid(EVP_MD_CTX_md(ctx));
struct sched_params params = {0};
__u32 i;
int ret;
- priv->e_nid = nid;
+ priv->e_nid = EVP_MD_nid(EVP_MD_CTX_md(ctx));
- digest_priv_ctx_cleanup(priv);
+ digest_priv_ctx_reset(priv);
ret = uadk_e_init_digest();
if (unlikely(!ret)) {
priv->switch_flag = UADK_DO_SOFT;
fprintf(stderr, "uadk failed to initialize digest.\n");
- goto soft_init;
+ return digest_soft_init(priv);
}
for (i = 0; i < digest_counts; i++) {
- if (nid == digest_info_table[i].nid) {
+ if (priv->e_nid == digest_info_table[i].nid) {
digest_priv_ctx_setup(priv, digest_info_table[i].alg,
digest_info_table[i].mode, digest_info_table[i].out_len);
break;
@@ -561,22 +657,30 @@ static int uadk_e_digest_init(EVP_MD_CTX *ctx)
/* Use the default numa parameters */
params.numa_id = -1;
priv->setup.sched_param = ¶ms;
- priv->sess = wd_digest_alloc_sess(&priv->setup);
- if (unlikely(!priv->sess))
- return 0;
+ if (!priv->sess) {
+ priv->sess = wd_digest_alloc_sess(&priv->setup);
+ if (unlikely(!priv->sess))
+ return 0;
- priv->data = malloc(DIGEST_BLOCK_SIZE);
- if (unlikely(!priv->data)) {
- wd_digest_free_sess(priv->sess);
- return 0;
+ priv->data = malloc(DIGEST_BLOCK_SIZE);
+ if (unlikely(!priv->data))
+ goto out;
+
+ if (!alloc_ctx_info(ctx)) {
+ free(priv->data);
+ priv->data = NULL;
+ goto out;
+ }
}
- priv->switch_threshold = sec_digest_get_sw_threshold(nid);
+ priv->switch_threshold = sec_digest_get_sw_threshold(priv->e_nid);
return 1;
-soft_init:
- return digest_soft_init(priv);
+out:
+ wd_digest_free_sess(priv->sess);
+ priv->sess = 0;
+ return 0;
}
static void digest_update_out_length(EVP_MD_CTX *ctx)
@@ -809,19 +913,36 @@ static int uadk_e_digest_cleanup(EVP_MD_CTX *ctx)
{
struct digest_priv_ctx *priv =
(struct digest_priv_ctx *)EVP_MD_CTX_md_data(ctx);
+ struct ctx_info *node = NULL;
- /* Prevent double-free after the copy is used */
- if (!priv || priv->copy)
+ if (!priv)
+ return 1;
+
+ pthread_mutex_lock(&digest_ctx_mutex);
+ find_ctx_info(ctx, &node);
+ if (node == NULL) {
+ pthread_mutex_unlock(&digest_ctx_mutex);
return 1;
+ }
+
+ /* If another ctx uses the same session, the session is not released */
+ if (is_ctx_sess_shared(node))
+ goto out;
+
+ if (priv->data) {
+ free(priv->data);
+ priv->data = NULL;
+ }
if (priv->sess) {
wd_digest_free_sess(priv->sess);
priv->sess = 0;
}
- if (priv && priv->data)
- free(priv->data);
-
+out:
+ del_ctx_info(node);
+ free(node);
+ pthread_mutex_unlock(&digest_ctx_mutex);
return 1;
}
@@ -831,6 +952,7 @@ static int uadk_e_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
(struct digest_priv_ctx *)EVP_MD_CTX_md_data(from);
struct digest_priv_ctx *t =
(struct digest_priv_ctx *)EVP_MD_CTX_md_data(to);
+ struct ctx_info *node = NULL;
/*
* EVP_MD_CTX_copy will copy from->priv to to->priv,
@@ -838,6 +960,26 @@ static int uadk_e_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
* add a flag to prevent double-free.
*/
+ pthread_mutex_lock(&digest_ctx_mutex);
+ find_ctx_info(to, &node);
+ if (node == NULL) {
+ node = malloc(sizeof(*node));
+ if (node == NULL) {
+ pthread_mutex_unlock(&digest_ctx_mutex);
+ return 0;
+ }
+ node->md_ctx = to;
+ add_ctx_info(node);
+ } else {
+ if (!is_ctx_sess_shared(node)) {
+ wd_digest_free_sess(node->sess);
+ free(node->data);
+ }
+ }
+ node->sess = t->sess;
+ node->data = t->data;
+ pthread_mutex_unlock(&digest_ctx_mutex);
+
if (f && f->data)
t->copy = true;
--
2.33.0