Skip to content

Commit d7860b6

Browse files
TexasTomriksgregkh
authored andcommitted
crypto: algif_skcipher - force synchronous processing
The AIO/async path in skcipher_recvmsg() passes the socket-wide ctx->iv directly into the skcipher request. After io_submit() the socket lock is dropped and the request is processed asynchronously by a worker (e.g. cryptd), which dereferences ctx->iv only later. A concurrent sendmsg(ALG_SET_IV) on the same socket can overwrite ctx->iv inside this window, so the in-flight request runs under an attacker-controlled IV. For CTR and other stream modes this causes IV/keystream reuse and allows an unprivileged user to recover the plaintext of a concurrent operation. Snapshotting ctx->iv into per-request storage for the async path is not sufficient here. For ciphers with statesize == 0 - which includes cbc and ctr - skcipher_prepare_alg() installs skcipher_noimport()/ skcipher_noexport(), so ctx->state carries nothing and the MSG_MORE inter-chunk IV chaining is carried solely by the in-place req->iv writeback. A snapshot redirects that writeback into per-request memory that af_alg_free_resources() releases on completion, so AIO + MSG_MORE with cbc/ctr would silently produce wrong output. Writing the IV back from the completion callback instead is not possible either: that would require lock_sock() there, but the callback can run in softirq/atomic context, so it must not sleep. Make the operation synchronous instead. ctx->iv is then only ever dereferenced under the socket lock held by recvmsg(), which removes the race, and the req->iv writeback lands in ctx->iv as before, which keeps MSG_MORE chaining intact for statesize == 0 ciphers. The ctx->state import/export path is unchanged for ciphers that do have state. This is equivalent to the upstream resolution: commit fcc77d3 ("net: Remove support for AIO on sockets") removed the AIO socket path across net/ entirely, producing the same end state for this file - algif_skcipher never processes an AIO request asynchronously. After this patch, _skcipher_recvmsg() matches mainline's crypto/algif_skcipher.c as it stands today, including the same now-dead -EIOCBQUEUED check. This patch deviates from that commit deliberately: rather than removing AIO socket support tree-wide, which would be far too invasive for stable, it removes only the AIO branch in crypto/algif_skcipher.c. io_submit() now completes synchronously, which is valid for the AIO interface; AF_ALG async is rarely used in practice. The -EIOCBQUEUED check in skcipher_recvmsg() is now dead but harmless, and is left alone to keep the fix minimal. Fixes: e870456 ("crypto: algif_skcipher - overhaul memory management") Cc: <stable@vger.kernel.org> Reported-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> Signed-off-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent de5a46f commit d7860b6

1 file changed

Lines changed: 24 additions & 51 deletions

File tree

crypto/algif_skcipher.c

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -79,20 +79,6 @@ static int algif_skcipher_export(struct sock *sk, struct skcipher_request *req)
7979
return err;
8080
}
8181

82-
static void algif_skcipher_done(void *data, int err)
83-
{
84-
struct af_alg_async_req *areq = data;
85-
struct sock *sk = areq->sk;
86-
87-
if (err)
88-
goto out;
89-
90-
err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req);
91-
92-
out:
93-
af_alg_async_cb(data, err);
94-
}
95-
9682
static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
9783
size_t ignored, int flags)
9884
{
@@ -171,43 +157,30 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
171157
cflags |= CRYPTO_SKCIPHER_REQ_CONT;
172158
}
173159

174-
if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) {
175-
/* AIO operation */
176-
sock_hold(sk);
177-
areq->iocb = msg->msg_iocb;
178-
179-
/* Remember output size that will be generated. */
180-
areq->outlen = len;
181-
182-
skcipher_request_set_callback(&areq->cra_u.skcipher_req,
183-
cflags |
184-
CRYPTO_TFM_REQ_MAY_SLEEP,
185-
algif_skcipher_done, areq);
186-
err = ctx->enc ?
187-
crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
188-
crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
189-
190-
/* AIO operation in progress */
191-
if (err == -EINPROGRESS)
192-
return -EIOCBQUEUED;
193-
194-
sock_put(sk);
195-
} else {
196-
/* Synchronous operation */
197-
skcipher_request_set_callback(&areq->cra_u.skcipher_req,
198-
cflags |
199-
CRYPTO_TFM_REQ_MAY_SLEEP |
200-
CRYPTO_TFM_REQ_MAY_BACKLOG,
201-
crypto_req_done, &ctx->wait);
202-
err = crypto_wait_req(ctx->enc ?
203-
crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
204-
crypto_skcipher_decrypt(&areq->cra_u.skcipher_req),
205-
&ctx->wait);
206-
207-
if (!err)
208-
err = algif_skcipher_export(
209-
sk, &areq->cra_u.skcipher_req);
210-
}
160+
/*
161+
* Force synchronous processing. The async (AIO) path passed the
162+
* socket-wide ctx->iv into the request, which the worker
163+
* dereferenced after the socket lock had been dropped, letting a
164+
* concurrent sendmsg(ALG_SET_IV) inject an attacker IV. Mainline
165+
* removed the AIO socket path in commit fcc77d33a34c ("net: Remove
166+
* support for AIO on sockets"); the minimal stable fix is to always
167+
* complete synchronously, so ctx->iv is only ever dereferenced under
168+
* the socket lock. This also keeps the IV chaining intact: for
169+
* ciphers with statesize == 0 (e.g. ctr, cbc) the chained IV is
170+
* carried by the req->iv writeback into ctx->iv, which is only
171+
* consistent on the synchronous path.
172+
*/
173+
skcipher_request_set_callback(&areq->cra_u.skcipher_req,
174+
cflags |
175+
CRYPTO_TFM_REQ_MAY_SLEEP |
176+
CRYPTO_TFM_REQ_MAY_BACKLOG,
177+
crypto_req_done, &ctx->wait);
178+
err = crypto_wait_req(ctx->enc ?
179+
crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
180+
crypto_skcipher_decrypt(&areq->cra_u.skcipher_req),
181+
&ctx->wait);
182+
if (!err)
183+
err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req);
211184

212185
free:
213186
af_alg_free_resources(areq);

0 commit comments

Comments
 (0)