Skip to content

Commit 2bf2901

Browse files
committed
crypto: api - Do not displace newly registered algorithms
We have a mechanism where newly registered algorithms of a higher priority can displace existing instances that use a different implementation of the same algorithm with a lower priority. Unfortunately the same mechanism can cause a newly registered algorithm to displace itself if it depends on an existing version of the same algorithm. This patch fixes this by keeping all algorithms that the newly reigstered algorithm depends on, thus protecting them from being removed. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent a367b17 commit 2bf2901

File tree

1 file changed

+63
-14
lines changed

1 file changed

+63
-14
lines changed

crypto/algapi.c

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,35 @@ static void crypto_destroy_instance(struct crypto_alg *alg)
8181
crypto_tmpl_put(tmpl);
8282
}
8383

84+
static struct list_head *crypto_more_spawns(struct crypto_alg *alg,
85+
struct list_head *stack,
86+
struct list_head *top,
87+
struct list_head *secondary_spawns)
88+
{
89+
struct crypto_spawn *spawn, *n;
90+
91+
if (list_empty(stack))
92+
return NULL;
93+
94+
spawn = list_first_entry(stack, struct crypto_spawn, list);
95+
n = list_entry(spawn->list.next, struct crypto_spawn, list);
96+
97+
if (spawn->alg && &n->list != stack && !n->alg)
98+
n->alg = (n->list.next == stack) ? alg :
99+
&list_entry(n->list.next, struct crypto_spawn,
100+
list)->inst->alg;
101+
102+
list_move(&spawn->list, secondary_spawns);
103+
104+
return &n->list == stack ? top : &n->inst->alg.cra_users;
105+
}
106+
84107
static void crypto_remove_spawn(struct crypto_spawn *spawn,
85-
struct list_head *list,
86-
struct list_head *secondary_spawns)
108+
struct list_head *list)
87109
{
88110
struct crypto_instance *inst = spawn->inst;
89111
struct crypto_template *tmpl = inst->tmpl;
90112

91-
list_del_init(&spawn->list);
92-
spawn->alg = NULL;
93-
94113
if (crypto_is_dead(&inst->alg))
95114
return;
96115

@@ -106,25 +125,55 @@ static void crypto_remove_spawn(struct crypto_spawn *spawn,
106125
hlist_del(&inst->list);
107126
inst->alg.cra_destroy = crypto_destroy_instance;
108127

109-
list_splice(&inst->alg.cra_users, secondary_spawns);
128+
BUG_ON(!list_empty(&inst->alg.cra_users));
110129
}
111130

112-
static void crypto_remove_spawns(struct list_head *spawns,
113-
struct list_head *list, u32 new_type)
131+
static void crypto_remove_spawns(struct crypto_alg *alg,
132+
struct list_head *list,
133+
struct crypto_alg *nalg)
114134
{
135+
u32 new_type = (nalg ?: alg)->cra_flags;
115136
struct crypto_spawn *spawn, *n;
116137
LIST_HEAD(secondary_spawns);
138+
struct list_head *spawns;
139+
LIST_HEAD(stack);
140+
LIST_HEAD(top);
117141

142+
spawns = &alg->cra_users;
118143
list_for_each_entry_safe(spawn, n, spawns, list) {
119144
if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
120145
continue;
121146

122-
crypto_remove_spawn(spawn, list, &secondary_spawns);
147+
list_move(&spawn->list, &top);
123148
}
124149

125-
while (!list_empty(&secondary_spawns)) {
126-
list_for_each_entry_safe(spawn, n, &secondary_spawns, list)
127-
crypto_remove_spawn(spawn, list, &secondary_spawns);
150+
spawns = &top;
151+
do {
152+
while (!list_empty(spawns)) {
153+
struct crypto_instance *inst;
154+
155+
spawn = list_first_entry(spawns, struct crypto_spawn,
156+
list);
157+
inst = spawn->inst;
158+
159+
BUG_ON(&inst->alg == alg);
160+
161+
list_move(&spawn->list, &stack);
162+
163+
if (&inst->alg == nalg)
164+
break;
165+
166+
spawn->alg = NULL;
167+
spawns = &inst->alg.cra_users;
168+
}
169+
} while ((spawns = crypto_more_spawns(alg, &stack, &top,
170+
&secondary_spawns)));
171+
172+
list_for_each_entry_safe(spawn, n, &secondary_spawns, list) {
173+
if (spawn->alg)
174+
list_move(&spawn->list, &spawn->alg->cra_users);
175+
else
176+
crypto_remove_spawn(spawn, list);
128177
}
129178
}
130179

@@ -258,7 +307,7 @@ void crypto_alg_tested(const char *name, int err)
258307
q->cra_priority > alg->cra_priority)
259308
continue;
260309

261-
crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags);
310+
crypto_remove_spawns(q, &list, alg);
262311
}
263312

264313
complete:
@@ -330,7 +379,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
330379

331380
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
332381
list_del_init(&alg->cra_list);
333-
crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags);
382+
crypto_remove_spawns(alg, list, NULL);
334383

335384
return 0;
336385
}

0 commit comments

Comments
 (0)