summaryrefslogtreecommitdiff
path: root/crypto/algif_skcipher.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/algif_skcipher.c')
-rw-r--r--crypto/algif_skcipher.c75
1 files changed, 24 insertions, 51 deletions
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index ba0a17fd95ac..35ebc3e0201b 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -79,20 +79,6 @@ static int algif_skcipher_export(struct sock *sk, struct skcipher_request *req)
return err;
}
-static void algif_skcipher_done(void *data, int err)
-{
- struct af_alg_async_req *areq = data;
- struct sock *sk = areq->sk;
-
- if (err)
- goto out;
-
- err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req);
-
-out:
- af_alg_async_cb(data, err);
-}
-
static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
size_t ignored, int flags)
{
@@ -171,43 +157,30 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
cflags |= CRYPTO_SKCIPHER_REQ_CONT;
}
- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) {
- /* AIO operation */
- sock_hold(sk);
- areq->iocb = msg->msg_iocb;
-
- /* Remember output size that will be generated. */
- areq->outlen = len;
-
- skcipher_request_set_callback(&areq->cra_u.skcipher_req,
- cflags |
- CRYPTO_TFM_REQ_MAY_SLEEP,
- algif_skcipher_done, areq);
- err = ctx->enc ?
- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
-
- /* AIO operation in progress */
- if (err == -EINPROGRESS)
- return -EIOCBQUEUED;
-
- sock_put(sk);
- } else {
- /* Synchronous operation */
- skcipher_request_set_callback(&areq->cra_u.skcipher_req,
- cflags |
- CRYPTO_TFM_REQ_MAY_SLEEP |
- CRYPTO_TFM_REQ_MAY_BACKLOG,
- crypto_req_done, &ctx->wait);
- err = crypto_wait_req(ctx->enc ?
- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req),
- &ctx->wait);
-
- if (!err)
- err = algif_skcipher_export(
- sk, &areq->cra_u.skcipher_req);
- }
+ /*
+ * Force synchronous processing. The async (AIO) path passed the
+ * socket-wide ctx->iv into the request, which the worker
+ * dereferenced after the socket lock had been dropped, letting a
+ * concurrent sendmsg(ALG_SET_IV) inject an attacker IV. Mainline
+ * removed the AIO socket path in commit fcc77d33a34c ("net: Remove
+ * support for AIO on sockets"); the minimal stable fix is to always
+ * complete synchronously, so ctx->iv is only ever dereferenced under
+ * the socket lock. This also keeps the IV chaining intact: for
+ * ciphers with statesize == 0 (e.g. ctr, cbc) the chained IV is
+ * carried by the req->iv writeback into ctx->iv, which is only
+ * consistent on the synchronous path.
+ */
+ skcipher_request_set_callback(&areq->cra_u.skcipher_req,
+ cflags |
+ CRYPTO_TFM_REQ_MAY_SLEEP |
+ CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done, &ctx->wait);
+ err = crypto_wait_req(ctx->enc ?
+ crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
+ crypto_skcipher_decrypt(&areq->cra_u.skcipher_req),
+ &ctx->wait);
+ if (!err)
+ err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req);
free:
af_alg_free_resources(areq);