crypto: af_alg - fix race accessing cipher request

When invoking an asynchronous cipher operation, the invocation of the
callback may be performed before the subsequent operations in the
initial code path are invoked. The callback deletes the cipher request
data structure which implies that after the invocation of the
asynchronous cipher operation, this data structure must not be accessed
any more.

The setting of the return code size with the request data structure must
therefore be moved before the invocation of the asynchronous cipher
operation.

Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management")
Fixes: d887c52d6ae4 ("crypto: algif_aead - overhaul memory management")
Reported-by: syzbot <syzkaller@googlegroups.com>
Cc: <stable@vger.kernel.org> # v4.14+
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by Stephan Mueller and committed by Herbert Xu d53c5135 9abffc6f

+10 -10
+5 -5
crypto/algif_aead.c
··· 291 /* AIO operation */ 292 sock_hold(sk); 293 areq->iocb = msg->msg_iocb; 294 aead_request_set_callback(&areq->cra_u.aead_req, 295 CRYPTO_TFM_REQ_MAY_BACKLOG, 296 af_alg_async_cb, areq); ··· 302 crypto_aead_decrypt(&areq->cra_u.aead_req); 303 304 /* AIO operation in progress */ 305 - if (err == -EINPROGRESS || err == -EBUSY) { 306 - /* Remember output size that will be generated. */ 307 - areq->outlen = outlen; 308 - 309 return -EIOCBQUEUED; 310 - } 311 312 sock_put(sk); 313 } else {
··· 291 /* AIO operation */ 292 sock_hold(sk); 293 areq->iocb = msg->msg_iocb; 294 + 295 + /* Remember output size that will be generated. */ 296 + areq->outlen = outlen; 297 + 298 aead_request_set_callback(&areq->cra_u.aead_req, 299 CRYPTO_TFM_REQ_MAY_BACKLOG, 300 af_alg_async_cb, areq); ··· 298 crypto_aead_decrypt(&areq->cra_u.aead_req); 299 300 /* AIO operation in progress */ 301 + if (err == -EINPROGRESS || err == -EBUSY) 302 return -EIOCBQUEUED; 303 304 sock_put(sk); 305 } else {
+5 -5
crypto/algif_skcipher.c
··· 125 /* AIO operation */ 126 sock_hold(sk); 127 areq->iocb = msg->msg_iocb; 128 skcipher_request_set_callback(&areq->cra_u.skcipher_req, 129 CRYPTO_TFM_REQ_MAY_SLEEP, 130 af_alg_async_cb, areq); ··· 137 crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); 138 139 /* AIO operation in progress */ 140 - if (err == -EINPROGRESS || err == -EBUSY) { 141 - /* Remember output size that will be generated. */ 142 - areq->outlen = len; 143 - 144 return -EIOCBQUEUED; 145 - } 146 147 sock_put(sk); 148 } else {
··· 125 /* AIO operation */ 126 sock_hold(sk); 127 areq->iocb = msg->msg_iocb; 128 + 129 + /* Remember output size that will be generated. */ 130 + areq->outlen = len; 131 + 132 skcipher_request_set_callback(&areq->cra_u.skcipher_req, 133 CRYPTO_TFM_REQ_MAY_SLEEP, 134 af_alg_async_cb, areq); ··· 133 crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); 134 135 /* AIO operation in progress */ 136 + if (err == -EINPROGRESS || err == -EBUSY) 137 return -EIOCBQUEUED; 138 139 sock_put(sk); 140 } else {