[PATCH OLK-5.10 00/11] Fix CVE-2026-31431
fix CVE-2026-31431. Douya Le (1): crypto: algif_aead - snapshot IV for async AEAD requests Eric Biggers (3): crypto: scatterwalk - Backport memcpy_sglist() crypto: algif_aead - use memcpy_sglist() instead of null skcipher crypto: authenc - use memcpy_sglist() instead of null skcipher Herbert Xu (5): crypto: algif_aead - Revert to operating out-of-place crypto: authencesn - Do not place hiseq at end of dst for out-of-place decryption crypto: authencesn - Fix src offset when decrypting in-place crypto: af_alg - Fix page reassignment overflow in af_alg_pull_tsgl crypto: algif_aead - Fix minimum RX size check for decryption Randy Dunlap (1): crypto: doc - fix kernel-doc notation in chacha.c and af_alg.c Taeyang Lee (1): crypto: authencesn - reject too-short AAD (assoclen<8) to match ESP/ESN spec crypto/Kconfig | 2 - crypto/af_alg.c | 137 +++++++++++------------ crypto/algif_aead.c | 203 ++++++++--------------------------- crypto/algif_skcipher.c | 6 +- crypto/authenc.c | 32 +----- crypto/authencesn.c | 88 +++++++-------- crypto/scatterwalk.c | 98 +++++++++++++++++ include/crypto/if_alg.h | 5 +- include/crypto/scatterwalk.h | 32 ++++++ lib/crypto/chacha.c | 4 +- 10 files changed, 277 insertions(+), 330 deletions(-) -- 2.34.1
From: Taeyang Lee <0wn@theori.io> stable inclusion from stable-v5.10.249 commit df22c9a65e9a9daa368a72fed596af9d7d5876bb category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- [ Upstream commit 2397e9264676be7794f8f7f1e9763d90bd3c7335 ] authencesn assumes an ESP/ESN-formatted AAD. When assoclen is shorter than the minimum expected length, crypto_authenc_esn_decrypt() can advance past the end of the destination scatterlist and trigger a NULL pointer dereference in scatterwalk_map_and_copy(), leading to a kernel panic (DoS). Add a minimum AAD length check to fail fast on invalid inputs. Fixes: 104880a6b470 ("crypto: authencesn - Convert to new AEAD interface") Reported-By: Taeyang Lee <0wn@theori.io> Signed-off-by: Taeyang Lee <0wn@theori.io> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/authencesn.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index b60e61b1904c..6487b35851d5 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -191,6 +191,9 @@ static int crypto_authenc_esn_encrypt(struct aead_request *req) struct scatterlist *src, *dst; int err; + if (assoclen < 8) + return -EINVAL; + sg_init_table(areq_ctx->src, 2); src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen); dst = src; @@ -284,6 +287,9 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req) u32 tmp[2]; int err; + if (assoclen < 8) + return -EINVAL; + cryptlen -= authsize; if (req->src != dst) { -- 2.34.1
From: Randy Dunlap <rdunlap@infradead.org> stable inclusion from stable-v5.10.254 commit 8b3843b1e3bc36f57d14d770fe0286a9cbeb38b1 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit b2a4411aca29ab7feb17c927d1d91d979361983c upstream. Fix function name in chacha.c kernel-doc comment to remove a warning. Convert af_alg.c to kernel-doc notation to eliminate many kernel-doc warnings. ../lib/crypto/chacha.c:77: warning: expecting prototype for chacha_block(). Prototype was for chacha_block_generic() instead chacha.c:104: warning: Excess function parameter 'out' description in 'hchacha_block_generic' af_alg.c:498: warning: Function parameter or member 'sk' not described in 'af_alg_alloc_tsgl' ../crypto/af_alg.c:539: warning: expecting prototype for aead_count_tsgl(). Prototype was for af_alg_count_tsgl() instead ../crypto/af_alg.c:596: warning: expecting prototype for aead_pull_tsgl(). Prototype was for af_alg_pull_tsgl() instead af_alg.c:663: warning: Function parameter or member 'areq' not described in 'af_alg_free_areq_sgls' af_alg.c:700: warning: Function parameter or member 'sk' not described in 'af_alg_wait_for_wmem' af_alg.c:700: warning: Function parameter or member 'flags' not described in 'af_alg_wait_for_wmem' af_alg.c:731: warning: Function parameter or member 'sk' not described in 'af_alg_wmem_wakeup' af_alg.c:757: warning: Function parameter or member 'sk' not described in 'af_alg_wait_for_data' af_alg.c:757: warning: Function parameter or member 'flags' not described in 'af_alg_wait_for_data' af_alg.c:757: warning: Function parameter or member 'min' not described in 'af_alg_wait_for_data' af_alg.c:796: warning: Function parameter or member 'sk' not described in 'af_alg_data_wakeup' af_alg.c:832: warning: Function parameter or member 'sock' not described in 'af_alg_sendmsg' af_alg.c:832: warning: Function parameter or member 'msg' not described in 'af_alg_sendmsg' af_alg.c:832: warning: Function parameter or member 'size' not described in 'af_alg_sendmsg' af_alg.c:832: warning: Function parameter or member 'ivsize' not described in 'af_alg_sendmsg' af_alg.c:985: warning: Function parameter or member 'sock' not described in 'af_alg_sendpage' af_alg.c:985: warning: Function parameter or member 'page' not described in 'af_alg_sendpage' af_alg.c:985: warning: Function parameter or member 'offset' not described in 'af_alg_sendpage' af_alg.c:985: warning: Function parameter or member 'size' not described in 'af_alg_sendpage' af_alg.c:985: warning: Function parameter or member 'flags' not described in 'af_alg_sendpage' af_alg.c:1040: warning: Function parameter or member 'areq' not described in 'af_alg_free_resources' af_alg.c:1059: warning: Function parameter or member '_req' not described in 'af_alg_async_cb' af_alg.c:1059: warning: Function parameter or member 'err' not described in 'af_alg_async_cb' af_alg.c:1083: warning: Function parameter or member 'file' not described in 'af_alg_poll' af_alg.c:1083: warning: Function parameter or member 'sock' not described in 'af_alg_poll' af_alg.c:1083: warning: Function parameter or member 'wait' not described in 'af_alg_poll' af_alg.c:1114: warning: Function parameter or member 'sk' not described in 'af_alg_alloc_areq' af_alg.c:1114: warning: Function parameter or member 'areqlen' not described in 'af_alg_alloc_areq' af_alg.c:1146: warning: Function parameter or member 'sk' not described in 'af_alg_get_rsgl' af_alg.c:1146: warning: Function parameter or member 'msg' not described in 'af_alg_get_rsgl' af_alg.c:1146: warning: Function parameter or member 'flags' not described in 'af_alg_get_rsgl' af_alg.c:1146: warning: Function parameter or member 'areq' not described in 'af_alg_get_rsgl' af_alg.c:1146: warning: Function parameter or member 'maxsize' not described in 'af_alg_get_rsgl' af_alg.c:1146: warning: Function parameter or member 'outlen' not described in 'af_alg_get_rsgl' Signed-off-by: Randy Dunlap <rdunlap@infradead.org> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: "David S. Miller" <davem@davemloft.net> Cc: linux-crypto@vger.kernel.org Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/af_alg.c | 94 +++++++++++++++++++++++++-------------------- lib/crypto/chacha.c | 4 +- 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index b7e132967650..430cf0f596d1 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -491,8 +491,8 @@ static int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) /** * af_alg_alloc_tsgl - allocate the TX SGL * - * @sk socket of connection to user space - * @return: 0 upon success, < 0 upon error + * @sk: socket of connection to user space + * Return: 0 upon success, < 0 upon error */ static int af_alg_alloc_tsgl(struct sock *sk) { @@ -525,15 +525,15 @@ static int af_alg_alloc_tsgl(struct sock *sk) } /** - * aead_count_tsgl - Count number of TX SG entries + * af_alg_count_tsgl - Count number of TX SG entries * * The counting starts from the beginning of the SGL to @bytes. If - * an offset is provided, the counting of the SG entries starts at the offset. + * an @offset is provided, the counting of the SG entries starts at the @offset. * - * @sk socket of connection to user space - * @bytes Count the number of SG entries holding given number of bytes. - * @offset Start the counting of SG entries from the given offset. - * @return Number of TX SG entries found given the constraints + * @sk: socket of connection to user space + * @bytes: Count the number of SG entries holding given number of bytes. + * @offset: Start the counting of SG entries from the given offset. + * Return: Number of TX SG entries found given the constraints */ unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) { @@ -577,19 +577,19 @@ unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) EXPORT_SYMBOL_GPL(af_alg_count_tsgl); /** - * aead_pull_tsgl - Release the specified buffers from TX SGL + * af_alg_pull_tsgl - Release the specified buffers from TX SGL * - * If @dst is non-null, reassign the pages to dst. The caller must release + * If @dst is non-null, reassign the pages to @dst. The caller must release * the pages. If @dst_offset is given only reassign the pages to @dst starting * at the @dst_offset (byte). The caller must ensure that @dst is large * enough (e.g. by using af_alg_count_tsgl with the same offset). * - * @sk socket of connection to user space - * @used Number of bytes to pull from TX SGL - * @dst If non-NULL, buffer is reassigned to dst SGL instead of releasing. The - * caller must release the buffers in dst. - * @dst_offset Reassign the TX SGL from given offset. All buffers before - * reaching the offset is released. + * @sk: socket of connection to user space + * @used: Number of bytes to pull from TX SGL + * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The + * caller must release the buffers in dst. + * @dst_offset: Reassign the TX SGL from given offset. All buffers before + * reaching the offset is released. */ void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, size_t dst_offset) @@ -657,7 +657,7 @@ EXPORT_SYMBOL_GPL(af_alg_pull_tsgl); /** * af_alg_free_areq_sgls - Release TX and RX SGLs of the request * - * @areq Request holding the TX and RX SGL + * @areq: Request holding the TX and RX SGL */ static void af_alg_free_areq_sgls(struct af_alg_async_req *areq) { @@ -692,9 +692,9 @@ static void af_alg_free_areq_sgls(struct af_alg_async_req *areq) /** * af_alg_wait_for_wmem - wait for availability of writable memory * - * @sk socket of connection to user space - * @flags If MSG_DONTWAIT is set, then only report if function would sleep - * @return 0 when writable memory is available, < 0 upon error + * @sk: socket of connection to user space + * @flags: If MSG_DONTWAIT is set, then only report if function would sleep + * Return: 0 when writable memory is available, < 0 upon error */ static int af_alg_wait_for_wmem(struct sock *sk, unsigned int flags) { @@ -725,7 +725,7 @@ static int af_alg_wait_for_wmem(struct sock *sk, unsigned int flags) /** * af_alg_wmem_wakeup - wakeup caller when writable memory is available * - * @sk socket of connection to user space + * @sk: socket of connection to user space */ void af_alg_wmem_wakeup(struct sock *sk) { @@ -748,10 +748,10 @@ EXPORT_SYMBOL_GPL(af_alg_wmem_wakeup); /** * af_alg_wait_for_data - wait for availability of TX data * - * @sk socket of connection to user space - * @flags If MSG_DONTWAIT is set, then only report if function would sleep - * @min Set to minimum request size if partial requests are allowed. - * @return 0 when writable memory is available, < 0 upon error + * @sk: socket of connection to user space + * @flags: If MSG_DONTWAIT is set, then only report if function would sleep + * @min: Set to minimum request size if partial requests are allowed. + * Return: 0 when writable memory is available, < 0 upon error */ int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min) { @@ -790,7 +790,7 @@ EXPORT_SYMBOL_GPL(af_alg_wait_for_data); /** * af_alg_data_wakeup - wakeup caller when new data can be sent to kernel * - * @sk socket of connection to user space + * @sk: socket of connection to user space */ static void af_alg_data_wakeup(struct sock *sk) { @@ -820,12 +820,12 @@ static void af_alg_data_wakeup(struct sock *sk) * * In addition, the ctx is filled with the information sent via CMSG. * - * @sock socket of connection to user space - * @msg message from user space - * @size size of message from user space - * @ivsize the size of the IV for the cipher operation to verify that the + * @sock: socket of connection to user space + * @msg: message from user space + * @size: size of message from user space + * @ivsize: the size of the IV for the cipher operation to verify that the * user-space-provided IV has the right size - * @return the number of copied data upon success, < 0 upon error + * Return: the number of copied data upon success, < 0 upon error */ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, unsigned int ivsize) @@ -979,6 +979,11 @@ EXPORT_SYMBOL_GPL(af_alg_sendmsg); /** * af_alg_sendpage - sendpage system call handler + * @sock: socket of connection to user space to write to + * @page: data to send + * @offset: offset into page to begin sending + * @size: length of data + * @flags: message send/receive flags * * This is a generic implementation of sendpage to fill ctx->tsgl_list. */ @@ -1037,6 +1042,7 @@ EXPORT_SYMBOL_GPL(af_alg_sendpage); /** * af_alg_free_resources - release resources required for crypto request + * @areq: Request holding the TX and RX SGL */ void af_alg_free_resources(struct af_alg_async_req *areq) { @@ -1053,6 +1059,9 @@ EXPORT_SYMBOL_GPL(af_alg_free_resources); /** * af_alg_async_cb - AIO callback handler + * @_req: async request info + * @err: if non-zero, error result to be returned via ki_complete(); + * otherwise return the AIO output length via ki_complete(). * * This handler cleans up the struct af_alg_async_req upon completion of the * AIO operation. @@ -1079,6 +1088,9 @@ EXPORT_SYMBOL_GPL(af_alg_async_cb); /** * af_alg_poll - poll system call handler + * @file: file pointer + * @sock: socket to poll + * @wait: poll_table */ __poll_t af_alg_poll(struct file *file, struct socket *sock, poll_table *wait) @@ -1104,9 +1116,9 @@ EXPORT_SYMBOL_GPL(af_alg_poll); /** * af_alg_alloc_areq - allocate struct af_alg_async_req * - * @sk socket of connection to user space - * @areqlen size of struct af_alg_async_req + crypto_*_reqsize - * @return allocated data structure or ERR_PTR upon error + * @sk: socket of connection to user space + * @areqlen: size of struct af_alg_async_req + crypto_*_reqsize + * Return: allocated data structure or ERR_PTR upon error */ struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk, unsigned int areqlen) @@ -1139,13 +1151,13 @@ EXPORT_SYMBOL_GPL(af_alg_alloc_areq); * af_alg_get_rsgl - create the RX SGL for the output data from the crypto * operation * - * @sk socket of connection to user space - * @msg user space message - * @flags flags used to invoke recvmsg with - * @areq instance of the cryptographic request that will hold the RX SGL - * @maxsize maximum number of bytes to be pulled from user space - * @outlen number of bytes in the RX SGL - * @return 0 on success, < 0 upon error + * @sk: socket of connection to user space + * @msg: user space message + * @flags: flags used to invoke recvmsg with + * @areq: instance of the cryptographic request that will hold the RX SGL + * @maxsize: maximum number of bytes to be pulled from user space + * @outlen: number of bytes in the RX SGL + * Return: 0 on success, < 0 upon error */ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, struct af_alg_async_req *areq, size_t maxsize, diff --git a/lib/crypto/chacha.c b/lib/crypto/chacha.c index 4ccbec442469..b748fd3d256e 100644 --- a/lib/crypto/chacha.c +++ b/lib/crypto/chacha.c @@ -64,7 +64,7 @@ static void chacha_permute(u32 *x, int nrounds) } /** - * chacha_block - generate one keystream block and increment block counter + * chacha_block_generic - generate one keystream block and increment block counter * @state: input state matrix (16 32-bit words) * @stream: output keystream block (64 bytes) * @nrounds: number of rounds (20 or 12; 20 is recommended) @@ -92,7 +92,7 @@ EXPORT_SYMBOL(chacha_block_generic); /** * hchacha_block_generic - abbreviated ChaCha core, for XChaCha * @state: input state matrix (16 32-bit words) - * @out: output (8 32-bit words) + * @stream: output (8 32-bit words) * @nrounds: number of rounds (20 or 12; 20 is recommended) * * HChaCha is the ChaCha equivalent of HSalsa and is an intermediate step -- 2.34.1
From: Eric Biggers <ebiggers@kernel.org> stable inclusion from stable-v5.10.254 commit 534b7f208c6019df5aacc249c6667845b1cc1dd3 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- This backports the current implementation of memcpy_sglist() from upstream commit 4dffc9bbffb9ccfcda730d899c97c553599e7ca8. This function was rewritten twice. The earlier implementations had many prerequisite commits, while the latest implementation is standalone. It's much easier to just backport the latest code directly. [5.10: replaced kmap_local and memcpy_page] Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/scatterwalk.c | 98 ++++++++++++++++++++++++++++++++++++ include/crypto/scatterwalk.h | 32 ++++++++++++ 2 files changed, 130 insertions(+) diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index 16f6ba896fb6..2858df87bd53 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -69,6 +69,104 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, } EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy); +/** + * memcpy_sglist() - Copy data from one scatterlist to another + * @dst: The destination scatterlist. Can be NULL if @nbytes == 0. + * @src: The source scatterlist. Can be NULL if @nbytes == 0. + * @nbytes: Number of bytes to copy + * + * The scatterlists can describe exactly the same memory, in which case this + * function is a no-op. No other overlaps are supported. + * + * Context: Any context + */ +void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + unsigned int src_offset, dst_offset; + + if (unlikely(nbytes == 0)) /* in case src and/or dst is NULL */ + return; + + src_offset = src->offset; + dst_offset = dst->offset; + for (;;) { + /* Compute the length to copy this step. */ + unsigned int len = min3(src->offset + src->length - src_offset, + dst->offset + dst->length - dst_offset, + nbytes); + struct page *src_page = sg_page(src); + struct page *dst_page = sg_page(dst); + const void *src_virt; + void *dst_virt; + + if (IS_ENABLED(CONFIG_HIGHMEM)) { + /* HIGHMEM: we may have to actually map the pages. */ + const unsigned int src_oip = offset_in_page(src_offset); + const unsigned int dst_oip = offset_in_page(dst_offset); + const unsigned int limit = PAGE_SIZE; + + /* Further limit len to not cross a page boundary. */ + len = min3(len, limit - src_oip, limit - dst_oip); + + /* Compute the source and destination pages. */ + src_page += src_offset / PAGE_SIZE; + dst_page += dst_offset / PAGE_SIZE; + + if (src_page != dst_page) { + /* Copy between different pages. */ + dst_virt = kmap_atomic(dst_page); + src_virt = kmap_atomic(src_page); + memcpy(dst_virt + dst_oip, src_virt + src_oip, + len); + kunmap_atomic((void *)src_virt); + kunmap_atomic(dst_virt); + flush_dcache_page(dst_page); + } else if (src_oip != dst_oip) { + /* Copy between different parts of same page. */ + dst_virt = kmap_atomic(dst_page); + memcpy(dst_virt + dst_oip, dst_virt + src_oip, + len); + kunmap_atomic(dst_virt); + flush_dcache_page(dst_page); + } /* Else, it's the same memory. No action needed. */ + } else { + /* + * !HIGHMEM: no mapping needed. Just work in the linear + * buffer of each sg entry. Note that we can cross page + * boundaries, as they are not significant in this case. + */ + src_virt = page_address(src_page) + src_offset; + dst_virt = page_address(dst_page) + dst_offset; + if (src_virt != dst_virt) { + memcpy(dst_virt, src_virt, len); + if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE) + __scatterwalk_flush_dcache_pages( + dst_page, dst_offset, len); + } /* Else, it's the same memory. No action needed. */ + } + nbytes -= len; + if (nbytes == 0) /* No more to copy? */ + break; + + /* + * There's more to copy. Advance the offsets by the length + * copied this step, and advance the sg entries as needed. + */ + src_offset += len; + if (src_offset >= src->offset + src->length) { + src = sg_next(src); + src_offset = src->offset; + } + dst_offset += len; + if (dst_offset >= dst->offset + dst->length) { + dst = sg_next(dst); + dst_offset = dst->offset; + } + } +} +EXPORT_SYMBOL_GPL(memcpy_sglist); + struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], struct scatterlist *src, unsigned int len) diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h index c837d0775474..a9b454d05613 100644 --- a/include/crypto/scatterwalk.h +++ b/include/crypto/scatterwalk.h @@ -93,6 +93,35 @@ static inline void scatterwalk_pagedone(struct scatter_walk *walk, int out, scatterwalk_start(walk, sg_next(walk->sg)); } +/* + * Flush the dcache of any pages that overlap the region + * [offset, offset + nbytes) relative to base_page. + * + * This should be called only when ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE, to ensure + * that all relevant code (including the call to sg_page() in the caller, if + * applicable) gets fully optimized out when !ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE. + */ +static inline void __scatterwalk_flush_dcache_pages(struct page *base_page, + unsigned int offset, + unsigned int nbytes) +{ + unsigned int num_pages; + unsigned int i; + + base_page += offset / PAGE_SIZE; + offset %= PAGE_SIZE; + + /* + * This is an overflow-safe version of + * num_pages = DIV_ROUND_UP(offset + nbytes, PAGE_SIZE). + */ + num_pages = nbytes / PAGE_SIZE; + num_pages += DIV_ROUND_UP(offset + (nbytes % PAGE_SIZE), PAGE_SIZE); + + for (i = 0; i < num_pages; i++) + flush_dcache_page(base_page + i); +} + static inline void scatterwalk_done(struct scatter_walk *walk, int out, int more) { @@ -105,6 +134,9 @@ void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); void *scatterwalk_map(struct scatter_walk *walk); +void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes); + void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, unsigned int start, unsigned int nbytes, int out); -- 2.34.1
From: Eric Biggers <ebiggers@google.com> stable inclusion from stable-v5.10.254 commit 488f9c3ab90e333ad5185d9236c1e10898acf041 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit f2804d0eee8ddd57aa79d0b82872b74c21e1b69b upstream. For copying data between two scatterlists, just use memcpy_sglist() instead of the so-called "null skcipher". This is much simpler. Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/Kconfig | 1 - crypto/algif_aead.c | 98 ++++++++------------------------------------- 2 files changed, 17 insertions(+), 82 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index fd87a70f1072..6b6b5d8c62a9 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -2017,7 +2017,6 @@ config CRYPTO_USER_API_AEAD depends on NET select CRYPTO_AEAD select CRYPTO_SKCIPHER - select CRYPTO_NULL select CRYPTO_USER_API help This option enables the user-spaces interface for AEAD diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 42493b4d8ce4..38a4ab8c90c7 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -27,7 +27,6 @@ #include <crypto/scatterwalk.h> #include <crypto/if_alg.h> #include <crypto/skcipher.h> -#include <crypto/null.h> #include <linux/init.h> #include <linux/list.h> #include <linux/kernel.h> @@ -36,19 +35,13 @@ #include <linux/net.h> #include <net/sock.h> -struct aead_tfm { - struct crypto_aead *aead; - struct crypto_sync_skcipher *null_tfm; -}; - static inline bool aead_sufficient_data(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); struct af_alg_ctx *ctx = ask->private; - struct aead_tfm *aeadc = pask->private; - struct crypto_aead *tfm = aeadc->aead; + struct crypto_aead *tfm = pask->private; unsigned int as = crypto_aead_authsize(tfm); /* @@ -64,27 +57,12 @@ static int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) struct alg_sock *ask = alg_sk(sk); struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); - struct aead_tfm *aeadc = pask->private; - struct crypto_aead *tfm = aeadc->aead; + struct crypto_aead *tfm = pask->private; unsigned int ivsize = crypto_aead_ivsize(tfm); return af_alg_sendmsg(sock, msg, size, ivsize); } -static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm, - struct scatterlist *src, - struct scatterlist *dst, unsigned int len) -{ - SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm); - - skcipher_request_set_sync_tfm(skreq, null_tfm); - skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP, - NULL, NULL); - skcipher_request_set_crypt(skreq, src, dst, len, NULL); - - return crypto_skcipher_encrypt(skreq); -} - static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) { @@ -93,9 +71,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); struct af_alg_ctx *ctx = ask->private; - struct aead_tfm *aeadc = pask->private; - struct crypto_aead *tfm = aeadc->aead; - struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; + struct crypto_aead *tfm = pask->private; unsigned int i, as = crypto_aead_authsize(tfm); struct af_alg_async_req *areq; struct af_alg_tsgl *tsgl, *tmp; @@ -223,10 +199,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, * v v * RX SGL: AAD || PT || Tag */ - err = crypto_aead_copy_sgl(null_tfm, tsgl_src, - areq->first_rsgl.sgl.sg, processed); - if (err) - goto free; + memcpy_sglist(areq->first_rsgl.sgl.sg, tsgl_src, processed); af_alg_pull_tsgl(sk, processed, NULL, 0); } else { /* @@ -240,11 +213,8 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, * RX SGL: AAD || CT ----+ */ - /* Copy AAD || CT to RX SGL buffer for in-place operation. */ - err = crypto_aead_copy_sgl(null_tfm, tsgl_src, - areq->first_rsgl.sgl.sg, outlen); - if (err) - goto free; + /* Copy AAD || CT to RX SGL buffer for in-place operation. */ + memcpy_sglist(areq->first_rsgl.sgl.sg, tsgl_src, outlen); /* Create TX SGL for tag and chain it to RX SGL. */ areq->tsgl_entries = af_alg_count_tsgl(sk, processed, @@ -378,7 +348,7 @@ static int aead_check_key(struct socket *sock) int err = 0; struct sock *psk; struct alg_sock *pask; - struct aead_tfm *tfm; + struct crypto_aead *tfm; struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); @@ -392,7 +362,7 @@ static int aead_check_key(struct socket *sock) err = -ENOKEY; lock_sock_nested(psk, SINGLE_DEPTH_NESTING); - if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) + if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) goto unlock; atomic_dec(&pask->nokey_refcnt); @@ -466,54 +436,22 @@ static struct proto_ops algif_aead_ops_nokey = { static void *aead_bind(const char *name, u32 type, u32 mask) { - struct aead_tfm *tfm; - struct crypto_aead *aead; - struct crypto_sync_skcipher *null_tfm; - - tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); - if (!tfm) - return ERR_PTR(-ENOMEM); - - aead = crypto_alloc_aead(name, type, mask); - if (IS_ERR(aead)) { - kfree(tfm); - return ERR_CAST(aead); - } - - null_tfm = crypto_get_default_null_skcipher(); - if (IS_ERR(null_tfm)) { - crypto_free_aead(aead); - kfree(tfm); - return ERR_CAST(null_tfm); - } - - tfm->aead = aead; - tfm->null_tfm = null_tfm; - - return tfm; + return crypto_alloc_aead(name, type, mask); } static void aead_release(void *private) { - struct aead_tfm *tfm = private; - - crypto_free_aead(tfm->aead); - crypto_put_default_null_skcipher(); - kfree(tfm); + crypto_free_aead(private); } static int aead_setauthsize(void *private, unsigned int authsize) { - struct aead_tfm *tfm = private; - - return crypto_aead_setauthsize(tfm->aead, authsize); + return crypto_aead_setauthsize(private, authsize); } static int aead_setkey(void *private, const u8 *key, unsigned int keylen) { - struct aead_tfm *tfm = private; - - return crypto_aead_setkey(tfm->aead, key, keylen); + return crypto_aead_setkey(private, key, keylen); } static void aead_sock_destruct(struct sock *sk) @@ -522,8 +460,7 @@ static void aead_sock_destruct(struct sock *sk) struct af_alg_ctx *ctx = ask->private; struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); - struct aead_tfm *aeadc = pask->private; - struct crypto_aead *tfm = aeadc->aead; + struct crypto_aead *tfm = pask->private; unsigned int ivlen = crypto_aead_ivsize(tfm); af_alg_pull_tsgl(sk, ctx->used, NULL, 0); @@ -536,10 +473,9 @@ static int aead_accept_parent_nokey(void *private, struct sock *sk) { struct af_alg_ctx *ctx; struct alg_sock *ask = alg_sk(sk); - struct aead_tfm *tfm = private; - struct crypto_aead *aead = tfm->aead; + struct crypto_aead *tfm = private; unsigned int len = sizeof(*ctx); - unsigned int ivlen = crypto_aead_ivsize(aead); + unsigned int ivlen = crypto_aead_ivsize(tfm); ctx = sock_kmalloc(sk, len, GFP_KERNEL); if (!ctx) @@ -566,9 +502,9 @@ static int aead_accept_parent_nokey(void *private, struct sock *sk) static int aead_accept_parent(void *private, struct sock *sk) { - struct aead_tfm *tfm = private; + struct crypto_aead *tfm = private; - if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) + if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) return -ENOKEY; return aead_accept_parent_nokey(private, sk); -- 2.34.1
From: Herbert Xu <herbert@gondor.apana.org.au> stable inclusion from stable-v5.10.254 commit 893d22e0135fa394db81df88697fba6032747667 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 upstream. This mostly reverts commit 72548b093ee3 except for the copying of the associated data. There is no benefit in operating in-place in algif_aead since the source and destination come from different mappings. Get rid of all the complexity added for in-place operation and just copy the AD directly. Fixes: 72548b093ee3 ("crypto: algif_aead - copy AAD from src to dst") Reported-by: Taeyang Lee <0wn@theori.io> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/af_alg.c | 49 +++++--------------- crypto/algif_aead.c | 99 ++++++++--------------------------------- crypto/algif_skcipher.c | 6 +-- include/crypto/if_alg.h | 5 +-- 4 files changed, 34 insertions(+), 125 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 430cf0f596d1..680c49d83fde 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -527,15 +527,13 @@ static int af_alg_alloc_tsgl(struct sock *sk) /** * af_alg_count_tsgl - Count number of TX SG entries * - * The counting starts from the beginning of the SGL to @bytes. If - * an @offset is provided, the counting of the SG entries starts at the @offset. + * The counting starts from the beginning of the SGL to @bytes. * * @sk: socket of connection to user space * @bytes: Count the number of SG entries holding given number of bytes. - * @offset: Start the counting of SG entries from the given offset. * Return: Number of TX SG entries found given the constraints */ -unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) +unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes) { const struct alg_sock *ask = alg_sk(sk); const struct af_alg_ctx *ctx = ask->private; @@ -550,25 +548,11 @@ unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) const struct scatterlist *sg = sgl->sg; for (i = 0; i < sgl->cur; i++) { - size_t bytes_count; - - /* Skip offset */ - if (offset >= sg[i].length) { - offset -= sg[i].length; - bytes -= sg[i].length; - continue; - } - - bytes_count = sg[i].length - offset; - - offset = 0; sgl_count++; - - /* If we have seen requested number of bytes, stop */ - if (bytes_count >= bytes) + if (sg[i].length >= bytes) return sgl_count; - bytes -= bytes_count; + bytes -= sg[i].length; } } @@ -580,19 +564,14 @@ EXPORT_SYMBOL_GPL(af_alg_count_tsgl); * af_alg_pull_tsgl - Release the specified buffers from TX SGL * * If @dst is non-null, reassign the pages to @dst. The caller must release - * the pages. If @dst_offset is given only reassign the pages to @dst starting - * at the @dst_offset (byte). The caller must ensure that @dst is large - * enough (e.g. by using af_alg_count_tsgl with the same offset). + * the pages. * * @sk: socket of connection to user space * @used: Number of bytes to pull from TX SGL * @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The * caller must release the buffers in dst. - * @dst_offset: Reassign the TX SGL from given offset. All buffers before - * reaching the offset is released. */ -void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, - size_t dst_offset) +void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst) { struct alg_sock *ask = alg_sk(sk); struct af_alg_ctx *ctx = ask->private; @@ -617,18 +596,10 @@ void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, * SG entries in dst. */ if (dst) { - if (dst_offset >= plen) { - /* discard page before offset */ - dst_offset -= plen; - } else { - /* reassign page to dst after offset */ - get_page(page); - sg_set_page(dst + j, page, - plen - dst_offset, - sg[i].offset + dst_offset); - dst_offset = 0; - j++; - } + /* reassign page to dst after offset */ + get_page(page); + sg_set_page(dst + j, page, plen, sg[i].offset); + j++; } sg[i].length -= plen; diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 38a4ab8c90c7..f59728c021fc 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -26,7 +26,6 @@ #include <crypto/internal/aead.h> #include <crypto/scatterwalk.h> #include <crypto/if_alg.h> -#include <crypto/skcipher.h> #include <linux/init.h> #include <linux/list.h> #include <linux/kernel.h> @@ -72,9 +71,8 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, struct alg_sock *pask = alg_sk(psk); struct af_alg_ctx *ctx = ask->private; struct crypto_aead *tfm = pask->private; - unsigned int i, as = crypto_aead_authsize(tfm); + unsigned int as = crypto_aead_authsize(tfm); struct af_alg_async_req *areq; - struct af_alg_tsgl *tsgl, *tmp; struct scatterlist *rsgl_src, *tsgl_src = NULL; int err = 0; size_t used = 0; /* [in] TX bufs to be en/decrypted */ @@ -154,23 +152,24 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, outlen -= less; } + /* + * Create a per request TX SGL for this request which tracks the + * SG entries from the global TX SGL. + */ processed = used + ctx->aead_assoclen; - list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) { - for (i = 0; i < tsgl->cur; i++) { - struct scatterlist *process_sg = tsgl->sg + i; - - if (!(process_sg->length) || !sg_page(process_sg)) - continue; - tsgl_src = process_sg; - break; - } - if (tsgl_src) - break; - } - if (processed && !tsgl_src) { - err = -EFAULT; + areq->tsgl_entries = af_alg_count_tsgl(sk, processed); + if (!areq->tsgl_entries) + areq->tsgl_entries = 1; + areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), + areq->tsgl_entries), + GFP_KERNEL); + if (!areq->tsgl) { + err = -ENOMEM; goto free; } + sg_init_table(areq->tsgl, areq->tsgl_entries); + af_alg_pull_tsgl(sk, processed, areq->tsgl); + tsgl_src = areq->tsgl; /* * Copy of AAD from source to destination @@ -179,75 +178,15 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, * when user space uses an in-place cipher operation, the kernel * will copy the data as it does not see whether such in-place operation * is initiated. - * - * To ensure efficiency, the following implementation ensure that the - * ciphers are invoked to perform a crypto operation in-place. This - * is achieved by memory management specified as follows. */ /* Use the RX SGL as source (and destination) for crypto op. */ rsgl_src = areq->first_rsgl.sgl.sg; - if (ctx->enc) { - /* - * Encryption operation - The in-place cipher operation is - * achieved by the following operation: - * - * TX SGL: AAD || PT - * | | - * | copy | - * v v - * RX SGL: AAD || PT || Tag - */ - memcpy_sglist(areq->first_rsgl.sgl.sg, tsgl_src, processed); - af_alg_pull_tsgl(sk, processed, NULL, 0); - } else { - /* - * Decryption operation - To achieve an in-place cipher - * operation, the following SGL structure is used: - * - * TX SGL: AAD || CT || Tag - * | | ^ - * | copy | | Create SGL link. - * v v | - * RX SGL: AAD || CT ----+ - */ - - /* Copy AAD || CT to RX SGL buffer for in-place operation. */ - memcpy_sglist(areq->first_rsgl.sgl.sg, tsgl_src, outlen); - - /* Create TX SGL for tag and chain it to RX SGL. */ - areq->tsgl_entries = af_alg_count_tsgl(sk, processed, - processed - as); - if (!areq->tsgl_entries) - areq->tsgl_entries = 1; - areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), - areq->tsgl_entries), - GFP_KERNEL); - if (!areq->tsgl) { - err = -ENOMEM; - goto free; - } - sg_init_table(areq->tsgl, areq->tsgl_entries); - - /* Release TX SGL, except for tag data and reassign tag data. */ - af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as); - - /* chain the areq TX SGL holding the tag with RX SGL */ - if (usedpages) { - /* RX SGL present */ - struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl; - - sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); - sg_chain(sgl_prev->sg, sgl_prev->npages + 1, - areq->tsgl); - } else - /* no RX SGL present (e.g. authentication only) */ - rsgl_src = areq->tsgl; - } + memcpy_sglist(rsgl_src, tsgl_src, ctx->aead_assoclen); /* Initialize the crypto operation */ - aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, + aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, areq->first_rsgl.sgl.sg, used, ctx->iv); aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); aead_request_set_tfm(&areq->cra_u.aead_req, tfm); @@ -463,7 +402,7 @@ static void aead_sock_destruct(struct sock *sk) struct crypto_aead *tfm = pask->private; unsigned int ivlen = crypto_aead_ivsize(tfm); - af_alg_pull_tsgl(sk, ctx->used, NULL, 0); + af_alg_pull_tsgl(sk, ctx->used, NULL); sock_kzfree_s(sk, ctx->iv, ivlen); sock_kfree_s(sk, ctx, ctx->len); af_alg_release_parent(sk); diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index bd9401e37706..edbdc19cdb31 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -95,7 +95,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, * Create a per request TX SGL for this request which tracks the * SG entries from the global TX SGL. */ - areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0); + areq->tsgl_entries = af_alg_count_tsgl(sk, len); if (!areq->tsgl_entries) areq->tsgl_entries = 1; areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), @@ -106,7 +106,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, goto free; } sg_init_table(areq->tsgl, areq->tsgl_entries); - af_alg_pull_tsgl(sk, len, areq->tsgl, 0); + af_alg_pull_tsgl(sk, len, areq->tsgl); /* Initialize the crypto operation */ skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); @@ -319,7 +319,7 @@ static void skcipher_sock_destruct(struct sock *sk) struct alg_sock *pask = alg_sk(psk); struct crypto_skcipher *tfm = pask->private; - af_alg_pull_tsgl(sk, ctx->used, NULL, 0); + af_alg_pull_tsgl(sk, ctx->used, NULL); sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); sock_kfree_s(sk, ctx, ctx->len); af_alg_release_parent(sk); diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index a406e281ae57..719a38d7e8bb 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -228,9 +228,8 @@ static inline bool af_alg_readable(struct sock *sk) return PAGE_SIZE <= af_alg_rcvbuf(sk); } -unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset); -void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst, - size_t dst_offset); +unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes); +void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst); void af_alg_wmem_wakeup(struct sock *sk); int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, -- 2.34.1
From: Douya Le <ldy3087146292@gmail.com> stable inclusion from stable-v5.10.254 commit 08ea39a556ecd39b33c2b4888861001c6706a62e category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit 5aa58c3a572b3e3b6c786953339f7978b845cc52 upstream. AF_ALG AEAD AIO requests currently use the socket-wide IV buffer during request processing. For async requests, later socket activity can update that shared state before the original request has fully completed, which can lead to inconsistent IV handling. Snapshot the IV into per-request storage when preparing the AEAD request, so in-flight operations no longer depend on mutable socket state. Fixes: d887c52d6ae4 ("crypto: algif_aead - overhaul memory management") Cc: stable@kernel.org Reported-by: Yuan Tan <yuantan098@gmail.com> Reported-by: Yifan Wu <yifanwucs@gmail.com> Reported-by: Juefei Pu <tomapufckgml@gmail.com> Reported-by: Xin Liu <bird@lzu.edu.cn> Co-developed-by: Luxing Yin <tr0jan@lzu.edu.cn> Signed-off-by: Luxing Yin <tr0jan@lzu.edu.cn> Tested-by: Yucheng Lu <kanolyc@gmail.com> Signed-off-by: Douya Le <ldy3087146292@gmail.com> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/algif_aead.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index f59728c021fc..24e77f4968a6 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -72,8 +72,10 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, struct af_alg_ctx *ctx = ask->private; struct crypto_aead *tfm = pask->private; unsigned int as = crypto_aead_authsize(tfm); + unsigned int ivsize = crypto_aead_ivsize(tfm); struct af_alg_async_req *areq; struct scatterlist *rsgl_src, *tsgl_src = NULL; + void *iv; int err = 0; size_t used = 0; /* [in] TX bufs to be en/decrypted */ size_t outlen = 0; /* [out] RX bufs produced by kernel */ @@ -125,10 +127,14 @@ static int _aead_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_aead_reqsize(tfm)); + crypto_aead_reqsize(tfm) + ivsize); if (IS_ERR(areq)) return PTR_ERR(areq); + iv = (u8 *)aead_request_ctx(&areq->cra_u.aead_req) + + crypto_aead_reqsize(tfm); + memcpy(iv, ctx->iv, ivsize); + /* convert iovecs of output buffers into RX SGL */ err = af_alg_get_rsgl(sk, msg, flags, areq, outlen, &usedpages); if (err) @@ -187,7 +193,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, /* Initialize the crypto operation */ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, - areq->first_rsgl.sgl.sg, used, ctx->iv); + areq->first_rsgl.sgl.sg, used, iv); aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); aead_request_set_tfm(&areq->cra_u.aead_req, tfm); -- 2.34.1
From: Eric Biggers <ebiggers@google.com> stable inclusion from stable-v5.10.254 commit 274857bb1fbef99ce4dba0f6e940115e17c48361 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit dbc4b1458e931e47198c3165ff5853bc1ad6bd7a upstream. For copying data between two scatterlists, just use memcpy_sglist() instead of the so-called "null skcipher". This is much simpler. Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/Kconfig | 1 - crypto/authenc.c | 32 +------------------------------- crypto/authencesn.c | 38 +++----------------------------------- 3 files changed, 4 insertions(+), 67 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 6b6b5d8c62a9..95aaf310277e 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -195,7 +195,6 @@ config CRYPTO_AUTHENC select CRYPTO_SKCIPHER select CRYPTO_MANAGER select CRYPTO_HASH - select CRYPTO_NULL help Authenc: Combined mode wrapper for IPsec. This is required for IPSec. diff --git a/crypto/authenc.c b/crypto/authenc.c index 17f674a7cdff..2b402e764529 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -9,7 +9,6 @@ #include <crypto/internal/hash.h> #include <crypto/internal/skcipher.h> #include <crypto/authenc.h> -#include <crypto/null.h> #include <crypto/scatterwalk.h> #include <linux/err.h> #include <linux/init.h> @@ -28,7 +27,6 @@ struct authenc_instance_ctx { struct crypto_authenc_ctx { struct crypto_ahash *auth; struct crypto_skcipher *enc; - struct crypto_sync_skcipher *null; }; struct authenc_request_ctx { @@ -174,21 +172,6 @@ static void crypto_authenc_encrypt_done(struct crypto_async_request *req, authenc_request_complete(areq, err); } -static int crypto_authenc_copy_assoc(struct aead_request *req) -{ - struct crypto_aead *authenc = crypto_aead_reqtfm(req); - struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); - SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); - - skcipher_request_set_sync_tfm(skreq, ctx->null); - skcipher_request_set_callback(skreq, aead_request_flags(req), - NULL, NULL); - skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen, - NULL); - - return crypto_skcipher_encrypt(skreq); -} - static int crypto_authenc_encrypt(struct aead_request *req) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); @@ -207,10 +190,7 @@ static int crypto_authenc_encrypt(struct aead_request *req) dst = src; if (req->src != req->dst) { - err = crypto_authenc_copy_assoc(req); - if (err) - return err; - + memcpy_sglist(req->dst, req->src, req->assoclen); dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); } @@ -311,7 +291,6 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm) struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm); struct crypto_ahash *auth; struct crypto_skcipher *enc; - struct crypto_sync_skcipher *null; int err; auth = crypto_spawn_ahash(&ictx->auth); @@ -323,14 +302,8 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm) if (IS_ERR(enc)) goto err_free_ahash; - null = crypto_get_default_null_skcipher(); - err = PTR_ERR(null); - if (IS_ERR(null)) - goto err_free_skcipher; - ctx->auth = auth; ctx->enc = enc; - ctx->null = null; crypto_aead_set_reqsize( tfm, @@ -344,8 +317,6 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm) return 0; -err_free_skcipher: - crypto_free_skcipher(enc); err_free_ahash: crypto_free_ahash(auth); return err; @@ -357,7 +328,6 @@ static void crypto_authenc_exit_tfm(struct crypto_aead *tfm) crypto_free_ahash(ctx->auth); crypto_free_skcipher(ctx->enc); - crypto_put_default_null_skcipher(); } static void crypto_authenc_free(struct aead_instance *inst) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 6487b35851d5..fceee6d67d34 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -12,7 +12,6 @@ #include <crypto/internal/hash.h> #include <crypto/internal/skcipher.h> #include <crypto/authenc.h> -#include <crypto/null.h> #include <crypto/scatterwalk.h> #include <linux/err.h> #include <linux/init.h> @@ -31,7 +30,6 @@ struct crypto_authenc_esn_ctx { unsigned int reqoff; struct crypto_ahash *auth; struct crypto_skcipher *enc; - struct crypto_sync_skcipher *null; }; struct authenc_esn_request_ctx { @@ -164,20 +162,6 @@ static void crypto_authenc_esn_encrypt_done(struct crypto_async_request *req, authenc_esn_request_complete(areq, err); } -static int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len) -{ - struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); - struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); - SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); - - skcipher_request_set_sync_tfm(skreq, ctx->null); - skcipher_request_set_callback(skreq, aead_request_flags(req), - NULL, NULL); - skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL); - - return crypto_skcipher_encrypt(skreq); -} - static int crypto_authenc_esn_encrypt(struct aead_request *req) { struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); @@ -199,10 +183,7 @@ static int crypto_authenc_esn_encrypt(struct aead_request *req) dst = src; if (req->src != req->dst) { - err = crypto_authenc_esn_copy(req, assoclen); - if (err) - return err; - + memcpy_sglist(req->dst, req->src, assoclen); sg_init_table(areq_ctx->dst, 2); dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen); } @@ -292,11 +273,8 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req) cryptlen -= authsize; - if (req->src != dst) { - err = crypto_authenc_esn_copy(req, assoclen + cryptlen); - if (err) - return err; - } + if (req->src != dst) + memcpy_sglist(dst, req->src, assoclen + cryptlen); scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen, authsize, 0); @@ -332,7 +310,6 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); struct crypto_ahash *auth; struct crypto_skcipher *enc; - struct crypto_sync_skcipher *null; int err; auth = crypto_spawn_ahash(&ictx->auth); @@ -344,14 +321,8 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) if (IS_ERR(enc)) goto err_free_ahash; - null = crypto_get_default_null_skcipher(); - err = PTR_ERR(null); - if (IS_ERR(null)) - goto err_free_skcipher; - ctx->auth = auth; ctx->enc = enc; - ctx->null = null; ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth), crypto_ahash_alignmask(auth) + 1); @@ -368,8 +339,6 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) return 0; -err_free_skcipher: - crypto_free_skcipher(enc); err_free_ahash: crypto_free_ahash(auth); return err; @@ -381,7 +350,6 @@ static void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm) crypto_free_ahash(ctx->auth); crypto_free_skcipher(ctx->enc); - crypto_put_default_null_skcipher(); } static void crypto_authenc_esn_free(struct aead_instance *inst) -- 2.34.1
From: Herbert Xu <herbert@gondor.apana.org.au> stable inclusion from stable-v5.10.254 commit 8c62f618576519dbed6816fafc623ce592953025 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit e02494114ebf7c8b42777c6cd6982f113bfdbec7 upstream. When decrypting data that is not in-place (src != dst), there is no need to save the high-order sequence bits in dst as it could simply be re-copied from the source. However, the data to be hashed need to be rearranged accordingly. Reported-by: Taeyang Lee <0wn@theori.io> Fixes: 104880a6b470 ("crypto: authencesn - Convert to new AEAD interface") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/authencesn.c | 48 +++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index fceee6d67d34..5dc057cb0cdf 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -214,6 +214,7 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, crypto_ahash_alignmask(auth) + 1); unsigned int cryptlen = req->cryptlen - authsize; unsigned int assoclen = req->assoclen; + struct scatterlist *src = req->src; struct scatterlist *dst = req->dst; u8 *ihash = ohash + crypto_ahash_digestsize(auth); u32 tmp[2]; @@ -221,23 +222,27 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, if (!authsize) goto decrypt; - /* Move high-order bits of sequence number back. */ - scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); - scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); - scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); + if (src == dst) { + /* Move high-order bits of sequence number back. */ + scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); + scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); + scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); + } else + memcpy_sglist(dst, src, assoclen); if (crypto_memneq(ihash, ohash, authsize)) return -EBADMSG; decrypt: - sg_init_table(areq_ctx->dst, 2); + if (src != dst) + src = scatterwalk_ffwd(areq_ctx->src, src, assoclen); dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen); skcipher_request_set_tfm(skreq, ctx->enc); skcipher_request_set_callback(skreq, flags, req->base.complete, req->base.data); - skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv); + skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv); return crypto_skcipher_decrypt(skreq); } @@ -264,6 +269,7 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req) unsigned int assoclen = req->assoclen; unsigned int cryptlen = req->cryptlen; u8 *ihash = ohash + crypto_ahash_digestsize(auth); + struct scatterlist *src = req->src; struct scatterlist *dst = req->dst; u32 tmp[2]; int err; @@ -271,24 +277,28 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req) if (assoclen < 8) return -EINVAL; - cryptlen -= authsize; - - if (req->src != dst) - memcpy_sglist(dst, req->src, assoclen + cryptlen); + if (!authsize) + goto tail; + cryptlen -= authsize; scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen, authsize, 0); - if (!authsize) - goto tail; - /* Move high-order bits of sequence number to the end. */ - scatterwalk_map_and_copy(tmp, dst, 0, 8, 0); - scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); - scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); - - sg_init_table(areq_ctx->dst, 2); - dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); + scatterwalk_map_and_copy(tmp, src, 0, 8, 0); + if (src == dst) { + scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); + scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); + dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); + } else { + scatterwalk_map_and_copy(tmp, dst, 0, 4, 1); + scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen - 4, 4, 1); + + src = scatterwalk_ffwd(areq_ctx->src, src, 8); + dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); + memcpy_sglist(dst, src, assoclen + cryptlen - 8); + dst = req->dst; + } ahash_request_set_tfm(ahreq, auth); ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen); -- 2.34.1
From: Herbert Xu <herbert@gondor.apana.org.au> stable inclusion from stable-v5.10.254 commit 88881da57e60ef796c59bf53bb34221c960ec707 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit 1f48ad3b19a9dfc947868edda0bb8e48e5b5a8fa upstream. The src SG list offset wasn't set properly when decrypting in-place, fix it. Reported-by: Wolfgang Walter <linux@stwm.de> Fixes: e02494114ebf ("crypto: authencesn - Do not place hiseq at end of dst for out-of-place decryption") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/authencesn.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 5dc057cb0cdf..2154d4ab5c95 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -235,9 +235,11 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, decrypt: - if (src != dst) - src = scatterwalk_ffwd(areq_ctx->src, src, assoclen); dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen); + if (req->src == req->dst) + src = dst; + else + src = scatterwalk_ffwd(areq_ctx->src, src, assoclen); skcipher_request_set_tfm(skreq, ctx->enc); skcipher_request_set_callback(skreq, flags, -- 2.34.1
From: Herbert Xu <herbert@gondor.apana.org.au> stable inclusion from stable-v5.10.254 commit fa48d3ea9cdbfb28c1fd6756c6c5cd01351aa51e category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit 31d00156e50ecad37f2cb6cbf04aaa9a260505ef upstream. When page reassignment was added to af_alg_pull_tsgl the original loop wasn't updated so it may try to reassign one more page than necessary. Add the check to the reassignment so that this does not happen. Also update the comment which still refers to the obsolete offset argument. Reported-by: syzbot+d23888375c2737c17ba5@syzkaller.appspotmail.com Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/af_alg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 680c49d83fde..30c08315d233 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -595,8 +595,8 @@ void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst) * Assumption: caller created af_alg_count_tsgl(len) * SG entries in dst. */ - if (dst) { - /* reassign page to dst after offset */ + if (dst && plen) { + /* reassign page to dst */ get_page(page); sg_set_page(dst + j, page, plen, sg[i].offset); j++; -- 2.34.1
From: Herbert Xu <herbert@gondor.apana.org.au> stable inclusion from stable-v5.10.254 commit 74a66fdb5282d89e348b00c42cfca3a936946d94 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14174 CVE: CVE-2026-31431 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit 3d14bd48e3a77091cbce637a12c2ae31b4a1687c upstream. The check for the minimum receive buffer size did not take the tag size into account during decryption. Fix this by adding the required extra length. Reported-by: syzbot+aa11561819dc42ebbc7c@syzkaller.appspotmail.com Reported-by: Daniel Pouzzner <douzzer@mega.nu> Fixes: d887c52d6ae4 ("crypto: algif_aead - overhaul memory management") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- crypto/algif_aead.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 24e77f4968a6..4a285994d106 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -150,7 +150,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, if (usedpages < outlen) { size_t less = outlen - usedpages; - if (used < less) { + if (used < less + (ctx->enc ? 0 : as)) { err = -EINVAL; goto free; } -- 2.34.1
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,转换为PR失败! 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/PNO... 失败原因:调用atomgit api创建PR失败, 失败原因如下: Another open merge request already exists for this source branch: !22139 建议解决方法:请稍等,机器人会在下一次任务重新执行 FeedBack: The patch(es) which you have sent to kernel@openeuler.org has been converted to PR failed! Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/PNO... Failed Reason: create PR failed when call atomgit's api, failed reason is as follows: Another open merge request already exists for this source branch: !22139 Suggest Solution: please wait, the bot will retry in the next interval
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/22140 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/PNO... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/22140 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/PNO...
participants (2)
-
patchwork bot -
Tengda Wu