Commit 4f87ee11 authored by Herbert Xu's avatar Herbert Xu
Browse files

crypto: api - Do not zap spawn->alg



Currently when a spawn is removed we will zap its alg field.
This is racy because the spawn could belong to an unregistered
instance which may dereference the spawn->alg field.

This patch fixes this by keeping spawn->alg constant and instead
adding a new spawn->dead field to indicate that a spawn is going
away.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 73669cc5
Loading
Loading
Loading
Loading
+12 −10
Original line number Diff line number Diff line
@@ -93,15 +93,17 @@ static struct list_head *crypto_more_spawns(struct crypto_alg *alg,
	if (!spawn)
		return NULL;

	n = list_next_entry(spawn, list);
	n = list_prev_entry(spawn, list);
	list_move(&spawn->list, secondary_spawns);

	if (spawn->alg && &n->list != stack && !n->alg)
		n->alg = (n->list.next == stack) ? alg :
			 &list_next_entry(n, list)->inst->alg;
	if (list_is_last(&n->list, stack))
		return top;

	list_move(&spawn->list, secondary_spawns);
	n = list_next_entry(n, list);
	if (!spawn->dead)
		n->dead = false;

	return &n->list == stack ? top : &n->inst->alg.cra_users;
	return &n->inst->alg.cra_users;
}

static void crypto_remove_instance(struct crypto_instance *inst,
@@ -160,7 +162,7 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
			if (&inst->alg == nalg)
				break;

			spawn->alg = NULL;
			spawn->dead = true;
			spawns = &inst->alg.cra_users;

			/*
@@ -179,7 +181,7 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
					      &secondary_spawns)));

	list_for_each_entry_safe(spawn, n, &secondary_spawns, list) {
		if (spawn->alg)
		if (!spawn->dead)
			list_move(&spawn->list, &spawn->alg->cra_users);
		else
			crypto_remove_instance(spawn->inst, list);
@@ -670,7 +672,7 @@ EXPORT_SYMBOL_GPL(crypto_grab_spawn);
void crypto_drop_spawn(struct crypto_spawn *spawn)
{
	down_write(&crypto_alg_sem);
	if (spawn->alg)
	if (!spawn->dead)
		list_del(&spawn->list);
	up_write(&crypto_alg_sem);
}
@@ -682,7 +684,7 @@ static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)

	down_read(&crypto_alg_sem);
	alg = spawn->alg;
	if (alg && !crypto_mod_get(alg)) {
	if (!spawn->dead && !crypto_mod_get(alg)) {
		alg->cra_flags |= CRYPTO_ALG_DYING;
		alg = NULL;
	}
+1 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ struct crypto_spawn {
	struct crypto_instance *inst;
	const struct crypto_type *frontend;
	u32 mask;
	bool dead;
};

struct crypto_queue {