* [PATCH 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees
@ 2026-07-05 22:01 Muhammet Kaan KILINÇ
2026-07-05 22:01 ` [PATCH 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests Muhammet Kaan KILINÇ
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Muhammet Kaan KILINÇ @ 2026-07-05 22:01 UTC (permalink / raw)
To: herbert, ebiggers; +Cc: linux-crypto, stable, sashal, Muhammet Kaan KILINÇ
The AF_ALG skcipher AIO path passes the socket-wide ctx->iv as a raw
pointer into the async request. After io_submit() the socket lock is
dropped and the request is processed by a worker, 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 is
IV/keystream reuse and lets an unprivileged user recover the
plaintext of a concurrent operation.
Mainline removed the AIO socket path entirely in commit fcc77d33a34c
("net: Remove support for AIO on sockets"), a broad net/ cleanup that is
not appropriate for a stable backport. The minimal stable fix mirrors the
algif_aead change 5aa58c3a572b ("crypto: algif_aead - snapshot IV for
async AEAD requests"). The supported stable trees split into two cases:
- 6.12.y and 6.19.y carry ctx->state, so a per-request IV snapshot is
sufficient (patch 1).
- 6.1.y and 6.6.y lack ctx->state and chain the IV in-place; there a
snapshot alone would break MSG_MORE chaining and a completion-path
writeback would reintroduce a race on ctx->iv outside the socket
lock, so the AIO path is made synchronous, matching the upstream
removal (patch 2). Patch 2 applies to both 6.1.y and 6.6.y.
This is distinct from CVE-2026-31677 (a skcipher receive-accounting
fix); it is an IV-handling race, not a receive-space guardrail.
Reported to security@kernel.org on 2026-06-07 (follow-up 2026-06-19, no
response). As the mainline removal is independent of that report and is
not backportable, I am sending the stable fix here.
Verified:
- 6.19.14 (patch 1): unpatched recovers plaintext on 2857/200000 AIO
ops (100% of injected cases); patched 0/0; MSG_MORE chunked output
bit-identical to single-shot.
- 6.6.143 (patch 2): unpatched injects the attacker IV on 2296/200000
ops; patched 0/200000; MSG_MORE chunked output bit-identical to
single-shot.
A working PoC is available to maintainers on request; it will be
published after the fix is picked up by the stable trees.
Muhammet Kaan KILINÇ (2):
crypto: algif_skcipher - snapshot IV for async skcipher requests
crypto: algif_skcipher - force synchronous processing on trees without
ctx->state
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests 2026-07-05 22:01 [PATCH 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees Muhammet Kaan KILINÇ @ 2026-07-05 22:01 ` Muhammet Kaan KILINÇ 2026-07-06 14:08 ` Sasha Levin 2026-07-05 22:01 ` [PATCH 2/2] crypto: algif_skcipher - force synchronous processing on trees without ctx->state Muhammet Kaan KILINÇ 2026-07-12 2:26 ` [PATCH v2 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees Muhammet Kaan KILINÇ 2 siblings, 1 reply; 9+ messages in thread From: Muhammet Kaan KILINÇ @ 2026-07-05 22:01 UTC (permalink / raw) To: herbert, ebiggers; +Cc: linux-crypto, stable, sashal, Muhammet Kaan KILINÇ 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. Fix this the same way as algif_aead (commit 5aa58c3a572b): allocate room for the IV in the request and operate on a per-request snapshot of ctx->iv instead of the shared pointer. IV chaining via ctx->state is unaffected: the snapshot is only the starting IV, and crypto_skcipher_import()/export() still carry the chained state across requests. Note: mainline removed AIO on sockets in commit fcc77d33a34c ("net: Remove support for AIO on sockets"), which closes this path there, but that is a feature removal and is not applicable to stable. The supported stable trees still contain the async path and remain affected, hence this minimal snapshot fix. Reported-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") Cc: <stable@vger.kernel.org> Signed-off-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> --- crypto/algif_skcipher.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index ba0a17f..6f6335f 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -103,7 +103,9 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, struct af_alg_ctx *ctx = ask->private; struct crypto_skcipher *tfm = pask->private; unsigned int bs = crypto_skcipher_chunksize(tfm); + unsigned int ivsize = crypto_skcipher_ivsize(tfm); struct af_alg_async_req *areq; + void *iv; unsigned cflags = 0; int err = 0; size_t len = 0; @@ -116,10 +118,14 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, /* Allocate cipher request for current operation. */ areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) + - crypto_skcipher_reqsize(tfm)); + crypto_skcipher_reqsize(tfm) + ivsize); if (IS_ERR(areq)) return PTR_ERR(areq); + iv = (u8 *)areq->cra_u.skcipher_req.__ctx + + crypto_skcipher_reqsize(tfm); + memcpy(iv, ctx->iv, ivsize); + /* convert iovecs of output buffers into RX SGL */ err = af_alg_get_rsgl(sk, msg, flags, areq, ctx->used, &len); if (err) @@ -159,7 +165,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, /* Initialize the crypto operation */ skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, - areq->first_rsgl.sgl.sgt.sgl, len, ctx->iv); + areq->first_rsgl.sgl.sgt.sgl, len, iv); if (ctx->state) { err = crypto_skcipher_import(&areq->cra_u.skcipher_req, -- 2.43.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests 2026-07-05 22:01 ` [PATCH 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests Muhammet Kaan KILINÇ @ 2026-07-06 14:08 ` Sasha Levin 2026-07-12 2:43 ` Muhammet Kaan Kılınç 0 siblings, 1 reply; 9+ messages in thread From: Sasha Levin @ 2026-07-06 14:08 UTC (permalink / raw) To: herbert, ebiggers Cc: Sasha Levin, linux-crypto, stable, Muhammet Kaan KILINÇ > 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. The race looks real, but the snapshot here is taken for synchronous requests too, and the updated IV is never written back to ctx->iv. That breaks implicit IV chaining across MSG_MORE fragments and back-to-back operations for cbc/ctr on a path that has no race to begin with. -- Thanks, Sasha ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests 2026-07-06 14:08 ` Sasha Levin @ 2026-07-12 2:43 ` Muhammet Kaan Kılınç 0 siblings, 0 replies; 9+ messages in thread From: Muhammet Kaan Kılınç @ 2026-07-12 2:43 UTC (permalink / raw) To: Sasha Levin; +Cc: herbert, ebiggers, linux-crypto, stable Thanks for the review, Sasha. v2 addresses both points: - The snapshot is now limited to the AIO branch; the sync path passes ctx->iv directly. - On the writeback: I initially implemented it in the completion callback, but that requires lock_sock() there, and the callback can run in softirq/atomic context on hardware skcipher backends -- a sleeping-in-atomic bug. Rather than convert the ctx->iv serialization to a spinlock (too invasive for stable), v2 follows the aead sibling 5aa58c3a572b and drops the writeback entirely. Implicit back-to-back AIO IV chaining is therefore not preserved; callers set the IV explicitly per request. MSG_MORE chaining is unaffected (carried by ctx->state, untouched). v2: https://lore.kernel.org/linux-crypto/20260712022618.1665-2-muhammetkaankilinc@gmail.com Thanks, Kaan On Mon, Jul 6, 2026 at 5:08 PM Sasha Levin <sashal@kernel.org> wrote: > > > 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. > > The race looks real, but the snapshot here is taken for synchronous > requests too, and the updated IV is never written back to ctx->iv. > That breaks implicit IV chaining across MSG_MORE fragments and > back-to-back operations for cbc/ctr on a path that has no race to > begin with. > > -- > Thanks, > Sasha ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/2] crypto: algif_skcipher - force synchronous processing on trees without ctx->state 2026-07-05 22:01 [PATCH 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees Muhammet Kaan KILINÇ 2026-07-05 22:01 ` [PATCH 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests Muhammet Kaan KILINÇ @ 2026-07-05 22:01 ` Muhammet Kaan KILINÇ 2026-07-12 2:26 ` [PATCH v2 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees Muhammet Kaan KILINÇ 2 siblings, 0 replies; 9+ messages in thread From: Muhammet Kaan KILINÇ @ 2026-07-05 22:01 UTC (permalink / raw) To: herbert, ebiggers; +Cc: linux-crypto, stable, sashal, Muhammet Kaan KILINÇ 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, so a concurrent sendmsg(ALG_SET_IV) can overwrite ctx->iv and make the in-flight request run under an attacker-controlled IV. For CTR/stream modes this is IV/keystream reuse and lets an unprivileged user recover the plaintext of a concurrent operation. Newer trees snapshot ctx->iv per request and rely on ctx->state (crypto_skcipher_import/export) to carry the chained IV. These trees lack ctx->state and chain the IV in-place, so a per-request snapshot alone would break MSG_MORE chaining, and a snapshot plus completion-time writeback would reintroduce a race on ctx->iv outside the socket lock. Make the operation synchronous instead, which removes both the IV race and any writeback race. This mirrors the upstream resolution, commit fcc77d33a34c ("net: Remove support for AIO on sockets"), which removed the AIO socket path entirely. io_submit() now completes synchronously; AF_ALG async is rarely used in practice. Tested on 6.6.y: attacker IV injection dropped from 2296/200000 to 0/200000 after the change; MSG_MORE chunked CTR output bit-identical to single-shot. Reported-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") Cc: <stable@vger.kernel.org> Signed-off-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> --- crypto/algif_skcipher.c | 49 +++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index e31b1da58..b12df4544 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -109,33 +109,20 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, - 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, - CRYPTO_TFM_REQ_MAY_SLEEP, - af_alg_async_cb, 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, - 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); - } + /* + * Force synchronous processing. The async (AIO) path passed the + * socket-wide ctx->iv into the request, which the worker + * dereferenced after the socket lock was 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"); these stable trees lack the + * per-request ctx->state used by newer kernels, so the minimal safe + * fix is to always complete synchronously. + */ + skcipher_request_set_callback(&areq->cra_u.skcipher_req, + 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); -- 2.43.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees 2026-07-05 22:01 [PATCH 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees Muhammet Kaan KILINÇ 2026-07-05 22:01 ` [PATCH 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests Muhammet Kaan KILINÇ 2026-07-05 22:01 ` [PATCH 2/2] crypto: algif_skcipher - force synchronous processing on trees without ctx->state Muhammet Kaan KILINÇ @ 2026-07-12 2:26 ` Muhammet Kaan KILINÇ 2026-07-12 2:26 ` [PATCH v2 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests Muhammet Kaan KILINÇ 2026-07-12 2:26 ` [PATCH v2 2/2] crypto: algif_skcipher - force synchronous processing on trees without ctx->state Muhammet Kaan KILINÇ 2 siblings, 2 replies; 9+ messages in thread From: Muhammet Kaan KILINÇ @ 2026-07-12 2:26 UTC (permalink / raw) To: sashal, herbert, ebiggers; +Cc: linux-crypto, stable, Muhammet Kaan KILINÇ The AF_ALG skcipher AIO path passes the socket-wide ctx->iv as a raw pointer into the async request. After io_submit() the socket lock is dropped and the request is processed by a worker, 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 is IV/keystream reuse and lets an unprivileged user recover the plaintext of a concurrent operation. This is the skcipher counterpart of commit 5aa58c3a572b ("crypto: algif_aead - snapshot IV for async AEAD requests"), which fixed the identical race in algif_aead. The fix here uses the same approach: operate on a per-request snapshot of ctx->iv instead of the shared pointer, for the AIO branch only. Like the aead fix, the updated IV is deliberately not written back to ctx->iv. Writing it back from the async completion callback would require lock_sock() there, but that callback can run in softirq/atomic context (a hardware skcipher driver may complete from a tasklet), so it must not sleep. Back-to-back AIO operations that relied on the implicit IV carry must instead set the IV explicitly per request (ALG_SET_IV), which is the documented usage. MSG_MORE chunked chaining is unaffected: it is carried by ctx->state via crypto_skcipher_export()/import(), independent of the IV snapshot. Mainline removed the AIO socket path entirely in commit fcc77d33a34c ("net: Remove support for AIO on sockets"), a broad net/ cleanup. There is therefore no mainline commit to backport: the sync/async split that creates this race was eliminated upstream along with the path, so mainline and its replacement are not affected by this bug class. This is submitted directly to stable under the documented exception in stable-kernel-rules.rst for fixes with no equivalent upstream commit. The supported stable trees split into two cases: - 6.12.y and 6.19.y carry ctx->state, so a per-request IV snapshot is sufficient (patch 1). - 6.1.y and 6.6.y lack ctx->state and chain the IV in-place; there a snapshot alone would break MSG_MORE chaining, so the AIO path is made synchronous, matching the upstream removal (patch 2). Patch 2 applies to both 6.1.y and 6.6.y. This is distinct from CVE-2026-31677 (a skcipher receive-accounting fix); it is an IV-handling race, not a receive-space guardrail. Reported to security@kernel.org on 2026-06-07 (follow-up 2026-06-19, no response). As the mainline removal is independent of that report and is not backportable, I am sending the stable fix here. Verified on 6.19.14 (patch 1): - Race: with a concurrent sendmsg(ALG_SET_IV) hammer against 200000 AIO ops, the attacker IV is injected 0 times on the patched kernel (v1 baseline reproduced plaintext recovery on 2857/200000 ops). - Correct usage still works: a known-answer AIO test (raw io_submit, AES-128-CTR) with an explicit per-request IV passes on both ctr(aes) inline completion and cryptd(ctr(aes-generic)) deferred completion. - As expected, relying on the implicit ctx->iv carry between two separate AIO ops no longer chains (this is the intentional behaviour change, matching aead); a negative control confirms the test is not vacuous. This supersedes v1: https://lore.kernel.org/linux-crypto/20260705220112.2522-1-muhammetkaankilinc@gmail.com Changes in v2 address Sasha Levin's review of patch 1: the IV snapshot is now limited to the AIO branch, and rather than writing the IV back under lock_sock() in the completion callback (which can run in atomic context), the fix follows the aead sibling and does not write back. Full per-patch changelog is below each patch's --- line. A working PoC is available to maintainers on request; it will be published after the fix is picked up by the stable trees. Muhammet Kaan KILINÇ (2): crypto: algif_skcipher - snapshot IV for async skcipher requests crypto: algif_skcipher - force synchronous processing on trees without ctx->state ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests 2026-07-12 2:26 ` [PATCH v2 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees Muhammet Kaan KILINÇ @ 2026-07-12 2:26 ` Muhammet Kaan KILINÇ 2026-07-12 20:27 ` Sasha Levin 2026-07-12 2:26 ` [PATCH v2 2/2] crypto: algif_skcipher - force synchronous processing on trees without ctx->state Muhammet Kaan KILINÇ 1 sibling, 1 reply; 9+ messages in thread From: Muhammet Kaan KILINÇ @ 2026-07-12 2:26 UTC (permalink / raw) To: sashal, herbert, ebiggers; +Cc: linux-crypto, stable, Muhammet Kaan KILINÇ 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. Fix this the same way as commit 5aa58c3a572b ("crypto: algif_aead - snapshot IV for async AEAD requests"): reserve room for the IV in the request and operate on a per-request snapshot of ctx->iv instead of the shared pointer. The snapshot is taken only for the AIO branch; the synchronous path passes ctx->iv directly. Like the aead fix, this does not write the cipher-updated IV back to ctx->iv: doing so from the async completion callback would require taking lock_sock() there, but that callback can run in softirq/atomic context, so it must not sleep. Back-to-back AIO operations that relied on the implicit IV carry must instead set the IV explicitly per request (ALG_SET_IV), which is the documented usage. MSG_MORE chunked chaining is unaffected: it is carried by ctx->state via crypto_skcipher_export()/import(), independent of the IV snapshot. Note: mainline removed AIO on sockets in commit fcc77d33a34c ("net: Remove support for AIO on sockets"), which closes this path there, but that is a feature removal and is not applicable to stable. The supported stable trees still contain the async path and remain affected, hence this minimal snapshot fix. Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") Cc: <stable@vger.kernel.org> Reported-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> Suggested-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> --- v2: Address Sasha Levin's review of v1. - Limit the IV snapshot to the AIO branch; the synchronous path now passes ctx->iv directly (v1 snapshotted unconditionally). - Do NOT write the updated IV back to ctx->iv. v1's missing writeback was intentional-in-hindsight: adding it in the async completion callback would require lock_sock() there, but that callback can run in softirq/atomic context (hardware skcipher drivers complete from a tasklet), so it must not sleep. This matches the accepted aead sibling 5aa58c3a572b, which also snapshots without writeback. Back-to-back AIO IV chaining via the implicit ctx->iv carry is therefore not preserved; callers must set the IV explicitly per request (ALG_SET_IV), the documented usage. MSG_MORE chunked chaining is unaffected (carried by ctx->state). The per-request IV is placed right after the tfm request context (skcipher_request_ctx() + reqsize), matching the aead sibling's non-DMA-aware placement. No skcipher template currently in tree uses crypto_skcipher_set_reqsize_dma(), so this needs no PTR_ALIGN. No Closes: tag: the underlying vulnerability was reported privately to security@kernel.org (2026-06-07), so there is no public report URL. crypto/algif_skcipher.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index ba0a17f..533e72d 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -103,7 +103,9 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, struct af_alg_ctx *ctx = ask->private; struct crypto_skcipher *tfm = pask->private; unsigned int bs = crypto_skcipher_chunksize(tfm); + unsigned int ivsize = crypto_skcipher_ivsize(tfm); struct af_alg_async_req *areq; + void *iv; unsigned cflags = 0; int err = 0; size_t len = 0; @@ -116,7 +118,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, /* Allocate cipher request for current operation. */ areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) + - crypto_skcipher_reqsize(tfm)); + crypto_skcipher_reqsize(tfm) + ivsize); if (IS_ERR(areq)) return PTR_ERR(areq); @@ -158,8 +160,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, /* Initialize the crypto operation */ skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); - skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, - areq->first_rsgl.sgl.sgt.sgl, len, ctx->iv); + iv = (u8 *)areq->cra_u.skcipher_req.__ctx + crypto_skcipher_reqsize(tfm); if (ctx->state) { err = crypto_skcipher_import(&areq->cra_u.skcipher_req, @@ -172,7 +173,10 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, } if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { - /* AIO operation */ + /* AIO operation: snapshot IV to avoid racing with ALG_SET_IV */ + memcpy(iv, ctx->iv, ivsize); + skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, + areq->first_rsgl.sgl.sgt.sgl, len, iv); sock_hold(sk); areq->iocb = msg->msg_iocb; @@ -194,6 +198,9 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, sock_put(sk); } else { /* Synchronous operation */ + skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, + areq->first_rsgl.sgl.sgt.sgl, len, + ctx->iv); skcipher_request_set_callback(&areq->cra_u.skcipher_req, cflags | CRYPTO_TFM_REQ_MAY_SLEEP | -- 2.43.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests 2026-07-12 2:26 ` [PATCH v2 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests Muhammet Kaan KILINÇ @ 2026-07-12 20:27 ` Sasha Levin 0 siblings, 0 replies; 9+ messages in thread From: Sasha Levin @ 2026-07-12 20:27 UTC (permalink / raw) To: herbert, ebiggers Cc: Sasha Levin, linux-crypto, stable, Muhammet Kaan KILINÇ > MSG_MORE chunked chaining is unaffected: it is carried by ctx->state via > crypto_skcipher_export()/import(), independent of the IV snapshot. This isn't true for cbc/ctr: their statesize is 0, so export/import carry nothing. The chained IV propagates only through the req->iv writeback, which this patch redirects into the freed snapshot - AIO + MSG_MORE cbc/ctr silently produces wrong output. -- Thanks, Sasha ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] crypto: algif_skcipher - force synchronous processing on trees without ctx->state 2026-07-12 2:26 ` [PATCH v2 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees Muhammet Kaan KILINÇ 2026-07-12 2:26 ` [PATCH v2 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests Muhammet Kaan KILINÇ @ 2026-07-12 2:26 ` Muhammet Kaan KILINÇ 1 sibling, 0 replies; 9+ messages in thread From: Muhammet Kaan KILINÇ @ 2026-07-12 2:26 UTC (permalink / raw) To: sashal, herbert, ebiggers; +Cc: linux-crypto, stable, Muhammet Kaan KILINÇ 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, so a concurrent sendmsg(ALG_SET_IV) can overwrite ctx->iv and make the in-flight request run under an attacker-controlled IV. For CTR/stream modes this is IV/keystream reuse and lets an unprivileged user recover the plaintext of a concurrent operation. Newer trees snapshot ctx->iv per request and rely on ctx->state (crypto_skcipher_import/export) to carry the chained IV. These trees lack ctx->state and chain the IV in-place, so a per-request snapshot alone would break MSG_MORE chaining, and a snapshot plus completion-time writeback would reintroduce a race on ctx->iv outside the socket lock. Make the operation synchronous instead, which removes both the IV race and any writeback race. This mirrors the upstream resolution, commit fcc77d33a34c ("net: Remove support for AIO on sockets"), which removed the AIO socket path entirely. io_submit() now completes synchronously; AF_ALG async is rarely used in practice. Tested on 6.6.y: attacker IV injection dropped from 2296/200000 to 0/200000 after the change; MSG_MORE chunked CTR output bit-identical to single-shot. Reported-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") Cc: <stable@vger.kernel.org> Signed-off-by: Muhammet Kaan KILINÇ <muhammetkaankilinc@gmail.com> --- v2: No functional change from v1. Independent of patch 1: patch 1 targets trees with ctx->state (6.12.y/6.19.y) and uses a per-request IV snapshot; this patch targets trees without ctx->state (6.1.y/6.6.y) and removes the async path entirely. There is no shared code path or state-detection logic between the two, so patch 1's v2 change (snapshot scope) does not affect this patch. crypto/algif_skcipher.c | 49 +++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index e31b1da58..b12df4544 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -109,33 +109,20 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, - 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, - CRYPTO_TFM_REQ_MAY_SLEEP, - af_alg_async_cb, 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, - 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); - } + /* + * Force synchronous processing. The async (AIO) path passed the + * socket-wide ctx->iv into the request, which the worker + * dereferenced after the socket lock was 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"); these stable trees lack the + * per-request ctx->state used by newer kernels, so the minimal safe + * fix is to always complete synchronously. + */ + skcipher_request_set_callback(&areq->cra_u.skcipher_req, + 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); -- 2.43.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-07-12 20:27 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-05 22:01 [PATCH 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees Muhammet Kaan KILINÇ 2026-07-05 22:01 ` [PATCH 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests Muhammet Kaan KILINÇ 2026-07-06 14:08 ` Sasha Levin 2026-07-12 2:43 ` Muhammet Kaan Kılınç 2026-07-05 22:01 ` [PATCH 2/2] crypto: algif_skcipher - force synchronous processing on trees without ctx->state Muhammet Kaan KILINÇ 2026-07-12 2:26 ` [PATCH v2 0/2] crypto: algif_skcipher - fix AIO IV race in stable trees Muhammet Kaan KILINÇ 2026-07-12 2:26 ` [PATCH v2 1/2] crypto: algif_skcipher - snapshot IV for async skcipher requests Muhammet Kaan KILINÇ 2026-07-12 20:27 ` Sasha Levin 2026-07-12 2:26 ` [PATCH v2 2/2] crypto: algif_skcipher - force synchronous processing on trees without ctx->state Muhammet Kaan KILINÇ
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox