Skip to content

Commit 016baaa

Browse files
committed
crypto: user - Fix crypto_alg_match race
The function crypto_alg_match returns an algorithm without taking any references on it. This means that the algorithm can be freed at any time, therefore all users of crypto_alg_match are buggy. This patch fixes this by taking a reference count on the algorithm to prevent such races. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent 9cd2232 commit 016baaa

1 file changed

Lines changed: 29 additions & 10 deletions

File tree

crypto/crypto_user.c

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,14 @@ static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact)
6262
else if (!exact)
6363
match = !strcmp(q->cra_name, p->cru_name);
6464

65-
if (match) {
66-
alg = q;
67-
break;
68-
}
65+
if (!match)
66+
continue;
67+
68+
if (unlikely(!crypto_mod_get(q)))
69+
continue;
70+
71+
alg = q;
72+
break;
6973
}
7074

7175
up_read(&crypto_alg_sem);
@@ -205,16 +209,21 @@ static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
205209
if (!alg)
206210
return -ENOENT;
207211

212+
err = -ENOMEM;
208213
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
209214
if (!skb)
210-
return -ENOMEM;
215+
goto drop_alg;
211216

212217
info.in_skb = in_skb;
213218
info.out_skb = skb;
214219
info.nlmsg_seq = in_nlh->nlmsg_seq;
215220
info.nlmsg_flags = 0;
216221

217222
err = crypto_report_alg(alg, &info);
223+
224+
drop_alg:
225+
crypto_mod_put(alg);
226+
218227
if (err)
219228
return err;
220229

@@ -284,6 +293,7 @@ static int crypto_update_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
284293

285294
up_write(&crypto_alg_sem);
286295

296+
crypto_mod_put(alg);
287297
crypto_remove_final(&list);
288298

289299
return 0;
@@ -294,6 +304,7 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
294304
{
295305
struct crypto_alg *alg;
296306
struct crypto_user_alg *p = nlmsg_data(nlh);
307+
int err;
297308

298309
if (!netlink_capable(skb, CAP_NET_ADMIN))
299310
return -EPERM;
@@ -310,13 +321,19 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
310321
* if we try to unregister. Unregistering such an algorithm without
311322
* removing the module is not possible, so we restrict to crypto
312323
* instances that are build from templates. */
324+
err = -EINVAL;
313325
if (!(alg->cra_flags & CRYPTO_ALG_INSTANCE))
314-
return -EINVAL;
326+
goto drop_alg;
315327

316-
if (atomic_read(&alg->cra_refcnt) != 1)
317-
return -EBUSY;
328+
err = -EBUSY;
329+
if (atomic_read(&alg->cra_refcnt) > 2)
330+
goto drop_alg;
318331

319-
return crypto_unregister_instance((struct crypto_instance *)alg);
332+
err = crypto_unregister_instance((struct crypto_instance *)alg);
333+
334+
drop_alg:
335+
crypto_mod_put(alg);
336+
return err;
320337
}
321338

322339
static struct crypto_alg *crypto_user_skcipher_alg(const char *name, u32 type,
@@ -395,8 +412,10 @@ static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
395412
return -EINVAL;
396413

397414
alg = crypto_alg_match(p, exact);
398-
if (alg)
415+
if (alg) {
416+
crypto_mod_put(alg);
399417
return -EEXIST;
418+
}
400419

401420
if (strlen(p->cru_driver_name))
402421
name = p->cru_driver_name;

0 commit comments

Comments
 (0)