* [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
* [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
* 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
* [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
* [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
* 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
* 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
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