Skip to content

Commit 0c1e16c

Browse files
smuellerDDherbertx
authored andcommitted
crypto: algif_aead - fix AEAD tag memory handling
For encryption, the AEAD ciphers require AAD || PT as input and generate AAD || CT || Tag as output and vice versa for decryption. Prior to this patch, the AF_ALG interface for AEAD ciphers requires the buffer to be present as input for encryption. Similarly, the output buffer for decryption required the presence of the tag buffer too. This implies that the kernel reads / writes data buffers from/to kernel space even though this operation is not required. This patch changes the AF_ALG AEAD interface to be consistent with the in-kernel AEAD cipher requirements. Due to this handling, he changes are transparent to user space with one exception: the return code of recv indicates the mount of output buffer. That output buffer has a different size compared to before the patch which implies that the return code of recv will also be different. For example, a decryption operation uses 16 bytes AAD, 16 bytes CT and 16 bytes tag, the AF_ALG AEAD interface before showed a recv return code of 48 (bytes) whereas after this patch, the return code is 32 since the tag is not returned any more. Reported-by: Mat Martineau <[email protected]> Signed-off-by: Stephan Mueller <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent 39eaf75 commit 0c1e16c

File tree

1 file changed

+36
-21
lines changed

1 file changed

+36
-21
lines changed

crypto/algif_aead.c

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ static inline bool aead_sufficient_data(struct aead_ctx *ctx)
8181
{
8282
unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req));
8383

84-
return ctx->used >= ctx->aead_assoclen + as;
84+
/*
85+
* The minimum amount of memory needed for an AEAD cipher is
86+
* the AAD and in case of decryption the tag.
87+
*/
88+
return ctx->used >= ctx->aead_assoclen + (ctx->enc ? 0 : as);
8589
}
8690

8791
static void aead_reset_ctx(struct aead_ctx *ctx)
@@ -426,12 +430,15 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
426430
goto unlock;
427431
}
428432

429-
used = ctx->used;
430-
outlen = used;
431-
432433
if (!aead_sufficient_data(ctx))
433434
goto unlock;
434435

436+
used = ctx->used;
437+
if (ctx->enc)
438+
outlen = used + as;
439+
else
440+
outlen = used - as;
441+
435442
req = sock_kmalloc(sk, reqlen, GFP_KERNEL);
436443
if (unlikely(!req))
437444
goto unlock;
@@ -445,7 +452,7 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
445452
aead_request_set_ad(req, ctx->aead_assoclen);
446453
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
447454
aead_async_cb, sk);
448-
used -= ctx->aead_assoclen + (ctx->enc ? as : 0);
455+
used -= ctx->aead_assoclen;
449456

450457
/* take over all tx sgls from ctx */
451458
areq->tsgl = sock_kmalloc(sk, sizeof(*areq->tsgl) * sgl->cur,
@@ -461,7 +468,7 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
461468
areq->tsgls = sgl->cur;
462469

463470
/* create rx sgls */
464-
while (iov_iter_count(&msg->msg_iter)) {
471+
while (outlen > usedpages && iov_iter_count(&msg->msg_iter)) {
465472
size_t seglen = min_t(size_t, iov_iter_count(&msg->msg_iter),
466473
(outlen - usedpages));
467474

@@ -491,16 +498,14 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
491498

492499
last_rsgl = rsgl;
493500

494-
/* we do not need more iovecs as we have sufficient memory */
495-
if (outlen <= usedpages)
496-
break;
497-
498501
iov_iter_advance(&msg->msg_iter, err);
499502
}
500-
err = -EINVAL;
503+
501504
/* ensure output buffer is sufficiently large */
502-
if (usedpages < outlen)
503-
goto free;
505+
if (usedpages < outlen) {
506+
err = -EINVAL;
507+
goto unlock;
508+
}
504509

505510
aead_request_set_crypt(req, areq->tsgl, areq->first_rsgl.sgl.sg, used,
506511
areq->iv);
@@ -571,6 +576,7 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
571576
goto unlock;
572577
}
573578

579+
/* data length provided by caller via sendmsg/sendpage */
574580
used = ctx->used;
575581

576582
/*
@@ -585,16 +591,27 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
585591
if (!aead_sufficient_data(ctx))
586592
goto unlock;
587593

588-
outlen = used;
594+
/*
595+
* Calculate the minimum output buffer size holding the result of the
596+
* cipher operation. When encrypting data, the receiving buffer is
597+
* larger by the tag length compared to the input buffer as the
598+
* encryption operation generates the tag. For decryption, the input
599+
* buffer provides the tag which is consumed resulting in only the
600+
* plaintext without a buffer for the tag returned to the caller.
601+
*/
602+
if (ctx->enc)
603+
outlen = used + as;
604+
else
605+
outlen = used - as;
589606

590607
/*
591608
* The cipher operation input data is reduced by the associated data
592609
* length as this data is processed separately later on.
593610
*/
594-
used -= ctx->aead_assoclen + (ctx->enc ? as : 0);
611+
used -= ctx->aead_assoclen;
595612

596613
/* convert iovecs of output buffers into scatterlists */
597-
while (iov_iter_count(&msg->msg_iter)) {
614+
while (outlen > usedpages && iov_iter_count(&msg->msg_iter)) {
598615
size_t seglen = min_t(size_t, iov_iter_count(&msg->msg_iter),
599616
(outlen - usedpages));
600617

@@ -621,16 +638,14 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
621638

622639
last_rsgl = rsgl;
623640

624-
/* we do not need more iovecs as we have sufficient memory */
625-
if (outlen <= usedpages)
626-
break;
627641
iov_iter_advance(&msg->msg_iter, err);
628642
}
629643

630-
err = -EINVAL;
631644
/* ensure output buffer is sufficiently large */
632-
if (usedpages < outlen)
645+
if (usedpages < outlen) {
646+
err = -EINVAL;
633647
goto unlock;
648+
}
634649

635650
sg_mark_end(sgl->sg + sgl->cur - 1);
636651
aead_request_set_crypt(&ctx->aead_req, sgl->sg, ctx->first_rsgl.sgl.sg,

0 commit comments

Comments
 (0)