lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ