Skip to content

Commit dcd4004

Browse files
smuellerDDgregkh
authored andcommitted
crypto: algif_aead - Require setkey before accept(2)
commit 2a2a251f110576b1d89efbd0662677d7e7db21a8 upstream. Some cipher implementations will crash if you try to use them without calling setkey first. This patch adds a check so that the accept(2) call will fail with -ENOKEY if setkey hasn't been done on the socket yet. Fixes: 400c40c ("crypto: algif - add AEAD support") Signed-off-by: Stephan Mueller <smueller@chronox.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 21cb4dc commit dcd4004

1 file changed

Lines changed: 149 additions & 8 deletions

File tree

crypto/algif_aead.c

Lines changed: 149 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ struct aead_sg_list {
2929
struct scatterlist sg[ALG_MAX_PAGES];
3030
};
3131

32+
struct aead_tfm {
33+
struct crypto_aead *aead;
34+
bool has_key;
35+
};
36+
3237
struct aead_ctx {
3338
struct aead_sg_list tsgl;
3439
/*
@@ -513,24 +518,146 @@ static struct proto_ops algif_aead_ops = {
513518
.poll = aead_poll,
514519
};
515520

521+
static int aead_check_key(struct socket *sock)
522+
{
523+
int err = 0;
524+
struct sock *psk;
525+
struct alg_sock *pask;
526+
struct aead_tfm *tfm;
527+
struct sock *sk = sock->sk;
528+
struct alg_sock *ask = alg_sk(sk);
529+
530+
lock_sock(sk);
531+
if (ask->refcnt)
532+
goto unlock_child;
533+
534+
psk = ask->parent;
535+
pask = alg_sk(ask->parent);
536+
tfm = pask->private;
537+
538+
err = -ENOKEY;
539+
lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
540+
if (!tfm->has_key)
541+
goto unlock;
542+
543+
if (!pask->refcnt++)
544+
sock_hold(psk);
545+
546+
ask->refcnt = 1;
547+
sock_put(psk);
548+
549+
err = 0;
550+
551+
unlock:
552+
release_sock(psk);
553+
unlock_child:
554+
release_sock(sk);
555+
556+
return err;
557+
}
558+
559+
static int aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
560+
size_t size)
561+
{
562+
int err;
563+
564+
err = aead_check_key(sock);
565+
if (err)
566+
return err;
567+
568+
return aead_sendmsg(sock, msg, size);
569+
}
570+
571+
static ssize_t aead_sendpage_nokey(struct socket *sock, struct page *page,
572+
int offset, size_t size, int flags)
573+
{
574+
int err;
575+
576+
err = aead_check_key(sock);
577+
if (err)
578+
return err;
579+
580+
return aead_sendpage(sock, page, offset, size, flags);
581+
}
582+
583+
static int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
584+
size_t ignored, int flags)
585+
{
586+
int err;
587+
588+
err = aead_check_key(sock);
589+
if (err)
590+
return err;
591+
592+
return aead_recvmsg(sock, msg, ignored, flags);
593+
}
594+
595+
static struct proto_ops algif_aead_ops_nokey = {
596+
.family = PF_ALG,
597+
598+
.connect = sock_no_connect,
599+
.socketpair = sock_no_socketpair,
600+
.getname = sock_no_getname,
601+
.ioctl = sock_no_ioctl,
602+
.listen = sock_no_listen,
603+
.shutdown = sock_no_shutdown,
604+
.getsockopt = sock_no_getsockopt,
605+
.mmap = sock_no_mmap,
606+
.bind = sock_no_bind,
607+
.accept = sock_no_accept,
608+
.setsockopt = sock_no_setsockopt,
609+
610+
.release = af_alg_release,
611+
.sendmsg = aead_sendmsg_nokey,
612+
.sendpage = aead_sendpage_nokey,
613+
.recvmsg = aead_recvmsg_nokey,
614+
.poll = aead_poll,
615+
};
616+
516617
static void *aead_bind(const char *name, u32 type, u32 mask)
517618
{
518-
return crypto_alloc_aead(name, type, mask);
619+
struct aead_tfm *tfm;
620+
struct crypto_aead *aead;
621+
622+
tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
623+
if (!tfm)
624+
return ERR_PTR(-ENOMEM);
625+
626+
aead = crypto_alloc_aead(name, type, mask);
627+
if (IS_ERR(aead)) {
628+
kfree(tfm);
629+
return ERR_CAST(aead);
630+
}
631+
632+
tfm->aead = aead;
633+
634+
return tfm;
519635
}
520636

521637
static void aead_release(void *private)
522638
{
523-
crypto_free_aead(private);
639+
struct aead_tfm *tfm = private;
640+
641+
crypto_free_aead(tfm->aead);
642+
kfree(tfm);
524643
}
525644

526645
static int aead_setauthsize(void *private, unsigned int authsize)
527646
{
528-
return crypto_aead_setauthsize(private, authsize);
647+
struct aead_tfm *tfm = private;
648+
649+
return crypto_aead_setauthsize(tfm->aead, authsize);
529650
}
530651

531652
static int aead_setkey(void *private, const u8 *key, unsigned int keylen)
532653
{
533-
return crypto_aead_setkey(private, key, keylen);
654+
struct aead_tfm *tfm = private;
655+
int err;
656+
657+
err = crypto_aead_setkey(tfm->aead, key, keylen);
658+
tfm->has_key = !err;
659+
660+
return err;
534661
}
535662

536663
static void aead_sock_destruct(struct sock *sk)
@@ -546,12 +673,14 @@ static void aead_sock_destruct(struct sock *sk)
546673
af_alg_release_parent(sk);
547674
}
548675

549-
static int aead_accept_parent(void *private, struct sock *sk)
676+
static int aead_accept_parent_nokey(void *private, struct sock *sk)
550677
{
551678
struct aead_ctx *ctx;
552679
struct alg_sock *ask = alg_sk(sk);
553-
unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(private);
554-
unsigned int ivlen = crypto_aead_ivsize(private);
680+
struct aead_tfm *tfm = private;
681+
struct crypto_aead *aead = tfm->aead;
682+
unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(aead);
683+
unsigned int ivlen = crypto_aead_ivsize(aead);
555684

556685
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
557686
if (!ctx)
@@ -577,7 +706,7 @@ static int aead_accept_parent(void *private, struct sock *sk)
577706

578707
ask->private = ctx;
579708

580-
aead_request_set_tfm(&ctx->aead_req, private);
709+
aead_request_set_tfm(&ctx->aead_req, aead);
581710
aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
582711
af_alg_complete, &ctx->completion);
583712

@@ -586,13 +715,25 @@ static int aead_accept_parent(void *private, struct sock *sk)
586715
return 0;
587716
}
588717

718+
static int aead_accept_parent(void *private, struct sock *sk)
719+
{
720+
struct aead_tfm *tfm = private;
721+
722+
if (!tfm->has_key)
723+
return -ENOKEY;
724+
725+
return aead_accept_parent_nokey(private, sk);
726+
}
727+
589728
static const struct af_alg_type algif_type_aead = {
590729
.bind = aead_bind,
591730
.release = aead_release,
592731
.setkey = aead_setkey,
593732
.setauthsize = aead_setauthsize,
594733
.accept = aead_accept_parent,
734+
.accept_nokey = aead_accept_parent_nokey,
595735
.ops = &algif_aead_ops,
736+
.ops_nokey = &algif_aead_ops_nokey,
596737
.name = "aead",
597738
.owner = THIS_MODULE
598739
};

0 commit comments

Comments
 (0)