[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251114122620.111623-1-coking@nvidia.com>
Date: Fri, 14 Nov 2025 12:26:19 +0000
From: Colin Ian King <coking@...dia.com>
To: Herbert Xu <herbert@...dor.apana.org.au>,
"David S . Miller" <davem@...emloft.net>,
linux-crypto@...r.kernel.org
Cc: kernel-janitors@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH] crypto: scatterwalk: propagate errors from failed call to skcipher_walk_first
There are cases where skcipher_walk_first can fail and errors such as
-ENOMEM or -EDEADLK are being ignored in memcpy_sglist. Add error checks
and propagate the error down to callers.
This fixes silent data loss from callers to memcpy_sglist (since walk is
zero'd) or potential encryption on the wrong data.
Signed-off-by: Colin Ian King <coking@...dia.com>
---
crypto/algif_aead.c | 8 ++++++--
crypto/authenc.c | 4 +++-
crypto/authencesn.c | 11 ++++++++---
crypto/chacha20poly1305.c | 8 ++++++--
crypto/echainiv.c | 9 +++++++--
crypto/gcm.c | 5 ++++-
crypto/scatterwalk.c | 11 ++++++++---
crypto/seqiv.c | 7 +++++--
include/crypto/scatterwalk.h | 2 +-
9 files changed, 48 insertions(+), 17 deletions(-)
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index 79b016a899a1..fd571bda0799 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -199,8 +199,10 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
* v v
* RX SGL: AAD || PT || Tag
*/
- memcpy_sglist(areq->first_rsgl.sgl.sgt.sgl, tsgl_src,
+ err = memcpy_sglist(areq->first_rsgl.sgl.sgt.sgl, tsgl_src,
processed);
+ if (err)
+ goto free;
af_alg_pull_tsgl(sk, processed, NULL, 0);
} else {
/*
@@ -215,7 +217,9 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
*/
/* Copy AAD || CT to RX SGL buffer for in-place operation. */
- memcpy_sglist(areq->first_rsgl.sgl.sgt.sgl, tsgl_src, outlen);
+ err = memcpy_sglist(areq->first_rsgl.sgl.sgt.sgl, tsgl_src, outlen);
+ if (err)
+ goto free;
/* Create TX SGL for tag and chain it to RX SGL. */
areq->tsgl_entries = af_alg_count_tsgl(sk, processed,
diff --git a/crypto/authenc.c b/crypto/authenc.c
index ac679ce2cb95..1abb4931ab59 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -202,7 +202,9 @@ static int crypto_authenc_encrypt(struct aead_request *req)
dst = src;
if (req->src != req->dst) {
- memcpy_sglist(req->dst, req->src, req->assoclen);
+ err = memcpy_sglist(req->dst, req->src, req->assoclen);
+ if (err)
+ return err;
dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen);
}
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
index d1bf0fda3f2e..6dc61dd4ab1a 100644
--- a/crypto/authencesn.c
+++ b/crypto/authencesn.c
@@ -174,7 +174,9 @@ static int crypto_authenc_esn_encrypt(struct aead_request *req)
dst = src;
if (req->src != req->dst) {
- memcpy_sglist(req->dst, req->src, assoclen);
+ err = memcpy_sglist(req->dst, req->src, assoclen);
+ if (err)
+ return err;
sg_init_table(areq_ctx->dst, 2);
dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen);
}
@@ -258,8 +260,11 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req)
cryptlen -= authsize;
- if (req->src != dst)
- memcpy_sglist(dst, req->src, assoclen + cryptlen);
+ if (req->src != dst) {
+ err = memcpy_sglist(dst, req->src, assoclen + cryptlen);
+ if (err)
+ return err;
+ }
scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen,
authsize, 0);
diff --git a/crypto/chacha20poly1305.c b/crypto/chacha20poly1305.c
index b4b5a7198d84..c15ae1a2d666 100644
--- a/crypto/chacha20poly1305.c
+++ b/crypto/chacha20poly1305.c
@@ -145,9 +145,13 @@ static int poly_hash(struct aead_request *req)
} tail;
unsigned int padlen;
unsigned int total;
+ int err;
- if (sg != req->dst)
- memcpy_sglist(req->dst, sg, req->assoclen);
+ if (sg != req->dst) {
+ err = memcpy_sglist(req->dst, sg, req->assoclen);
+ if (err)
+ return err;
+ }
if (rctx->cryptlen == req->cryptlen) /* encrypting */
sg = req->dst;
diff --git a/crypto/echainiv.c b/crypto/echainiv.c
index e0a2d3209938..d46fb04c16f4 100644
--- a/crypto/echainiv.c
+++ b/crypto/echainiv.c
@@ -40,9 +40,14 @@ static int echainiv_encrypt(struct aead_request *req)
info = req->iv;
- if (req->src != req->dst)
- memcpy_sglist(req->dst, req->src,
+ if (req->src != req->dst) {
+ int err;
+
+ err = memcpy_sglist(req->dst, req->src,
req->assoclen + req->cryptlen);
+ if (err)
+ return err;
+ }
aead_request_set_callback(subreq, req->base.flags,
req->base.complete, req->base.data);
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 97716482bed0..2c40df82ad20 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -928,10 +928,13 @@ static int crypto_rfc4543_crypt(struct aead_request *req, bool enc)
crypto_aead_alignmask(ctx->child) + 1);
if (req->src != req->dst) {
+ int err;
unsigned int nbytes = req->assoclen + req->cryptlen -
(enc ? 0 : authsize);
- memcpy_sglist(req->dst, req->src, nbytes);
+ err = memcpy_sglist(req->dst, req->src, nbytes);
+ if (err)
+ return err;
}
memcpy(iv, ctx->nonce, 4);
diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c
index 1d010e2a1b1a..021368d1c519 100644
--- a/crypto/scatterwalk.c
+++ b/crypto/scatterwalk.c
@@ -101,26 +101,31 @@ void memcpy_to_sglist(struct scatterlist *sg, unsigned int start,
}
EXPORT_SYMBOL_GPL(memcpy_to_sglist);
-void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src,
+int memcpy_sglist(struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
struct skcipher_walk walk = {};
+ int err;
if (unlikely(nbytes == 0)) /* in case sg == NULL */
- return;
+ return 0;
walk.total = nbytes;
scatterwalk_start(&walk.in, src);
scatterwalk_start(&walk.out, dst);
- skcipher_walk_first(&walk, true);
+ err = skcipher_walk_first(&walk, true);
+ if (err)
+ return err;
do {
if (walk.src.virt.addr != walk.dst.virt.addr)
memcpy(walk.dst.virt.addr, walk.src.virt.addr,
walk.nbytes);
skcipher_walk_done(&walk, 0);
} while (walk.nbytes);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(memcpy_sglist);
diff --git a/crypto/seqiv.c b/crypto/seqiv.c
index 2bae99e33526..bfb484b2514f 100644
--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -64,9 +64,12 @@ static int seqiv_aead_encrypt(struct aead_request *req)
data = req->base.data;
info = req->iv;
- if (req->src != req->dst)
- memcpy_sglist(req->dst, req->src,
+ if (req->src != req->dst) {
+ err = memcpy_sglist(req->dst, req->src,
req->assoclen + req->cryptlen);
+ if (err)
+ return err;
+ }
if (unlikely(!IS_ALIGNED((unsigned long)info,
crypto_aead_alignmask(geniv) + 1))) {
diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h
index 83d14376ff2b..ee9fa43bc82e 100644
--- a/include/crypto/scatterwalk.h
+++ b/include/crypto/scatterwalk.h
@@ -278,7 +278,7 @@ void memcpy_from_sglist(void *buf, struct scatterlist *sg,
void memcpy_to_sglist(struct scatterlist *sg, unsigned int start,
const void *buf, unsigned int nbytes);
-void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src,
+int memcpy_sglist(struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes);
/* In new code, please use memcpy_{from,to}_sglist() directly instead. */
--
2.51.0
Powered by blists - more mailing lists