@@ -81,7 +81,11 @@ static inline bool aead_sufficient_data(struct aead_ctx *ctx)
81
81
{
82
82
unsigned as = crypto_aead_authsize (crypto_aead_reqtfm (& ctx -> aead_req ));
83
83
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 );
85
89
}
86
90
87
91
static void aead_reset_ctx (struct aead_ctx * ctx )
@@ -416,7 +420,7 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
416
420
unsigned int i , reqlen = GET_REQ_SIZE (tfm );
417
421
int err = - ENOMEM ;
418
422
unsigned long used ;
419
- size_t outlen ;
423
+ size_t outlen = 0 ;
420
424
size_t usedpages = 0 ;
421
425
422
426
lock_sock (sk );
@@ -426,12 +430,15 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
426
430
goto unlock ;
427
431
}
428
432
429
- used = ctx -> used ;
430
- outlen = used ;
431
-
432
433
if (!aead_sufficient_data (ctx ))
433
434
goto unlock ;
434
435
436
+ used = ctx -> used ;
437
+ if (ctx -> enc )
438
+ outlen = used + as ;
439
+ else
440
+ outlen = used - as ;
441
+
435
442
req = sock_kmalloc (sk , reqlen , GFP_KERNEL );
436
443
if (unlikely (!req ))
437
444
goto unlock ;
@@ -445,7 +452,7 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
445
452
aead_request_set_ad (req , ctx -> aead_assoclen );
446
453
aead_request_set_callback (req , CRYPTO_TFM_REQ_MAY_BACKLOG ,
447
454
aead_async_cb , sk );
448
- used -= ctx -> aead_assoclen + ( ctx -> enc ? as : 0 ) ;
455
+ used -= ctx -> aead_assoclen ;
449
456
450
457
/* take over all tx sgls from ctx */
451
458
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,
461
468
areq -> tsgls = sgl -> cur ;
462
469
463
470
/* create rx sgls */
464
- while (iov_iter_count (& msg -> msg_iter )) {
471
+ while (outlen > usedpages && iov_iter_count (& msg -> msg_iter )) {
465
472
size_t seglen = min_t (size_t , iov_iter_count (& msg -> msg_iter ),
466
473
(outlen - usedpages ));
467
474
@@ -491,16 +498,14 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
491
498
492
499
last_rsgl = rsgl ;
493
500
494
- /* we do not need more iovecs as we have sufficient memory */
495
- if (outlen <= usedpages )
496
- break ;
497
-
498
501
iov_iter_advance (& msg -> msg_iter , err );
499
502
}
500
- err = - EINVAL ;
503
+
501
504
/* ensure output buffer is sufficiently large */
502
- if (usedpages < outlen )
503
- goto free ;
505
+ if (usedpages < outlen ) {
506
+ err = - EINVAL ;
507
+ goto unlock ;
508
+ }
504
509
505
510
aead_request_set_crypt (req , areq -> tsgl , areq -> first_rsgl .sgl .sg , used ,
506
511
areq -> iv );
@@ -571,6 +576,7 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
571
576
goto unlock ;
572
577
}
573
578
579
+ /* data length provided by caller via sendmsg/sendpage */
574
580
used = ctx -> used ;
575
581
576
582
/*
@@ -585,16 +591,27 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
585
591
if (!aead_sufficient_data (ctx ))
586
592
goto unlock ;
587
593
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 ;
589
606
590
607
/*
591
608
* The cipher operation input data is reduced by the associated data
592
609
* length as this data is processed separately later on.
593
610
*/
594
- used -= ctx -> aead_assoclen + ( ctx -> enc ? as : 0 ) ;
611
+ used -= ctx -> aead_assoclen ;
595
612
596
613
/* 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 )) {
598
615
size_t seglen = min_t (size_t , iov_iter_count (& msg -> msg_iter ),
599
616
(outlen - usedpages ));
600
617
@@ -621,16 +638,14 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
621
638
622
639
last_rsgl = rsgl ;
623
640
624
- /* we do not need more iovecs as we have sufficient memory */
625
- if (outlen <= usedpages )
626
- break ;
627
641
iov_iter_advance (& msg -> msg_iter , err );
628
642
}
629
643
630
- err = - EINVAL ;
631
644
/* ensure output buffer is sufficiently large */
632
- if (usedpages < outlen )
645
+ if (usedpages < outlen ) {
646
+ err = - EINVAL ;
633
647
goto unlock ;
648
+ }
634
649
635
650
sg_mark_end (sgl -> sg + sgl -> cur - 1 );
636
651
aead_request_set_crypt (& ctx -> aead_req , sgl -> sg , ctx -> first_rsgl .sgl .sg ,
0 commit comments