Skip to content

Commit 9e03d0e

Browse files
kerneltoastroxanan1996
authored andcommitted
crypto: algif_aead - Revert to operating out-of-place
jira VULN-181879 cve CVE-2026-31431 commit-author Herbert Xu <herbert@gondor.apana.org.au> commit a664bf3 upstream-diff | This kernel lacks upstream commits c1abe6f ("crypto: af_alg: Use extract_iter_to_sg() to create scatterlists") and f2804d0 ("crypto: algif_aead - use memcpy_sglist() instead of null skcipher"). As a result, there are two conflicts: the scatterlist table is located in a different member of `struct af_alg_sgl` and the null skcipher is used for copying between scatterlists instead of memcpy_sglist() (which is a helper that doesn't exist in this kernel version). The scatterlist table discrepancy is resolved by using the correct member of `struct af_alg_sgl`. The upstream patch's usage of memcpy_sglist() is replaced by a call to the null skcipher to perform the scatterlist copy instead. This mostly reverts commit 72548b0 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: 72548b0 ("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> (cherry picked from commit a664bf3) Signed-off-by: Sultan Alsawaf <sultan@ciq.com>
1 parent b2740b4 commit 9e03d0e

4 files changed

Lines changed: 37 additions & 131 deletions

File tree

crypto/af_alg.c

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -524,15 +524,13 @@ static int af_alg_alloc_tsgl(struct sock *sk)
524524
/**
525525
* af_alg_count_tsgl - Count number of TX SG entries
526526
*
527-
* The counting starts from the beginning of the SGL to @bytes. If
528-
* an @offset is provided, the counting of the SG entries starts at the @offset.
527+
* The counting starts from the beginning of the SGL to @bytes.
529528
*
530529
* @sk: socket of connection to user space
531530
* @bytes: Count the number of SG entries holding given number of bytes.
532-
* @offset: Start the counting of SG entries from the given offset.
533531
* Return: Number of TX SG entries found given the constraints
534532
*/
535-
unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset)
533+
unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes)
536534
{
537535
const struct alg_sock *ask = alg_sk(sk);
538536
const struct af_alg_ctx *ctx = ask->private;
@@ -547,25 +545,11 @@ unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset)
547545
const struct scatterlist *sg = sgl->sg;
548546

549547
for (i = 0; i < sgl->cur; i++) {
550-
size_t bytes_count;
551-
552-
/* Skip offset */
553-
if (offset >= sg[i].length) {
554-
offset -= sg[i].length;
555-
bytes -= sg[i].length;
556-
continue;
557-
}
558-
559-
bytes_count = sg[i].length - offset;
560-
561-
offset = 0;
562548
sgl_count++;
563-
564-
/* If we have seen requested number of bytes, stop */
565-
if (bytes_count >= bytes)
549+
if (sg[i].length >= bytes)
566550
return sgl_count;
567551

568-
bytes -= bytes_count;
552+
bytes -= sg[i].length;
569553
}
570554
}
571555

@@ -577,19 +561,14 @@ EXPORT_SYMBOL_GPL(af_alg_count_tsgl);
577561
* af_alg_pull_tsgl - Release the specified buffers from TX SGL
578562
*
579563
* If @dst is non-null, reassign the pages to @dst. The caller must release
580-
* the pages. If @dst_offset is given only reassign the pages to @dst starting
581-
* at the @dst_offset (byte). The caller must ensure that @dst is large
582-
* enough (e.g. by using af_alg_count_tsgl with the same offset).
564+
* the pages.
583565
*
584566
* @sk: socket of connection to user space
585567
* @used: Number of bytes to pull from TX SGL
586568
* @dst: If non-NULL, buffer is reassigned to dst SGL instead of releasing. The
587569
* caller must release the buffers in dst.
588-
* @dst_offset: Reassign the TX SGL from given offset. All buffers before
589-
* reaching the offset is released.
590570
*/
591-
void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
592-
size_t dst_offset)
571+
void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst)
593572
{
594573
struct alg_sock *ask = alg_sk(sk);
595574
struct af_alg_ctx *ctx = ask->private;
@@ -614,18 +593,10 @@ void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
614593
* SG entries in dst.
615594
*/
616595
if (dst) {
617-
if (dst_offset >= plen) {
618-
/* discard page before offset */
619-
dst_offset -= plen;
620-
} else {
621-
/* reassign page to dst after offset */
622-
get_page(page);
623-
sg_set_page(dst + j, page,
624-
plen - dst_offset,
625-
sg[i].offset + dst_offset);
626-
dst_offset = 0;
627-
j++;
628-
}
596+
/* reassign page to dst after offset */
597+
get_page(page);
598+
sg_set_page(dst + j, page, plen, sg[i].offset);
599+
j++;
629600
}
630601

631602
sg[i].length -= plen;

crypto/algif_aead.c

Lines changed: 22 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include <crypto/internal/aead.h>
2727
#include <crypto/scatterwalk.h>
2828
#include <crypto/if_alg.h>
29-
#include <crypto/skcipher.h>
3029
#include <crypto/null.h>
3130
#include <linux/init.h>
3231
#include <linux/list.h>
@@ -96,9 +95,8 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
9695
struct aead_tfm *aeadc = pask->private;
9796
struct crypto_aead *tfm = aeadc->aead;
9897
struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm;
99-
unsigned int i, as = crypto_aead_authsize(tfm);
98+
unsigned int as = crypto_aead_authsize(tfm);
10099
struct af_alg_async_req *areq;
101-
struct af_alg_tsgl *tsgl, *tmp;
102100
struct scatterlist *rsgl_src, *tsgl_src = NULL;
103101
int err = 0;
104102
size_t used = 0; /* [in] TX bufs to be en/decrypted */
@@ -178,23 +176,24 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
178176
outlen -= less;
179177
}
180178

179+
/*
180+
* Create a per request TX SGL for this request which tracks the
181+
* SG entries from the global TX SGL.
182+
*/
181183
processed = used + ctx->aead_assoclen;
182-
list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) {
183-
for (i = 0; i < tsgl->cur; i++) {
184-
struct scatterlist *process_sg = tsgl->sg + i;
185-
186-
if (!(process_sg->length) || !sg_page(process_sg))
187-
continue;
188-
tsgl_src = process_sg;
189-
break;
190-
}
191-
if (tsgl_src)
192-
break;
193-
}
194-
if (processed && !tsgl_src) {
195-
err = -EFAULT;
184+
areq->tsgl_entries = af_alg_count_tsgl(sk, processed);
185+
if (!areq->tsgl_entries)
186+
areq->tsgl_entries = 1;
187+
areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
188+
areq->tsgl_entries),
189+
GFP_KERNEL);
190+
if (!areq->tsgl) {
191+
err = -ENOMEM;
196192
goto free;
197193
}
194+
sg_init_table(areq->tsgl, areq->tsgl_entries);
195+
af_alg_pull_tsgl(sk, processed, areq->tsgl);
196+
tsgl_src = areq->tsgl;
198197

199198
/*
200199
* Copy of AAD from source to destination
@@ -203,81 +202,18 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
203202
* when user space uses an in-place cipher operation, the kernel
204203
* will copy the data as it does not see whether such in-place operation
205204
* is initiated.
206-
*
207-
* To ensure efficiency, the following implementation ensure that the
208-
* ciphers are invoked to perform a crypto operation in-place. This
209-
* is achieved by memory management specified as follows.
210205
*/
211206

212207
/* Use the RX SGL as source (and destination) for crypto op. */
213208
rsgl_src = areq->first_rsgl.sgl.sg;
214209

215-
if (ctx->enc) {
216-
/*
217-
* Encryption operation - The in-place cipher operation is
218-
* achieved by the following operation:
219-
*
220-
* TX SGL: AAD || PT
221-
* | |
222-
* | copy |
223-
* v v
224-
* RX SGL: AAD || PT || Tag
225-
*/
226-
err = crypto_aead_copy_sgl(null_tfm, tsgl_src,
227-
areq->first_rsgl.sgl.sg, processed);
228-
if (err)
229-
goto free;
230-
af_alg_pull_tsgl(sk, processed, NULL, 0);
231-
} else {
232-
/*
233-
* Decryption operation - To achieve an in-place cipher
234-
* operation, the following SGL structure is used:
235-
*
236-
* TX SGL: AAD || CT || Tag
237-
* | | ^
238-
* | copy | | Create SGL link.
239-
* v v |
240-
* RX SGL: AAD || CT ----+
241-
*/
242-
243-
/* Copy AAD || CT to RX SGL buffer for in-place operation. */
244-
err = crypto_aead_copy_sgl(null_tfm, tsgl_src,
245-
areq->first_rsgl.sgl.sg, outlen);
246-
if (err)
247-
goto free;
248-
249-
/* Create TX SGL for tag and chain it to RX SGL. */
250-
areq->tsgl_entries = af_alg_count_tsgl(sk, processed,
251-
processed - as);
252-
if (!areq->tsgl_entries)
253-
areq->tsgl_entries = 1;
254-
areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
255-
areq->tsgl_entries),
256-
GFP_KERNEL);
257-
if (!areq->tsgl) {
258-
err = -ENOMEM;
259-
goto free;
260-
}
261-
sg_init_table(areq->tsgl, areq->tsgl_entries);
262-
263-
/* Release TX SGL, except for tag data and reassign tag data. */
264-
af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as);
265-
266-
/* chain the areq TX SGL holding the tag with RX SGL */
267-
if (usedpages) {
268-
/* RX SGL present */
269-
struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl;
270-
271-
sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1);
272-
sg_chain(sgl_prev->sg, sgl_prev->npages + 1,
273-
areq->tsgl);
274-
} else
275-
/* no RX SGL present (e.g. authentication only) */
276-
rsgl_src = areq->tsgl;
277-
}
210+
err = crypto_aead_copy_sgl(null_tfm, tsgl_src, rsgl_src,
211+
ctx->aead_assoclen);
212+
if (err)
213+
goto free;
278214

279215
/* Initialize the crypto operation */
280-
aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src,
216+
aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src,
281217
areq->first_rsgl.sgl.sg, used, ctx->iv);
282218
aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen);
283219
aead_request_set_tfm(&areq->cra_u.aead_req, tfm);
@@ -526,7 +462,7 @@ static void aead_sock_destruct(struct sock *sk)
526462
struct crypto_aead *tfm = aeadc->aead;
527463
unsigned int ivlen = crypto_aead_ivsize(tfm);
528464

529-
af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
465+
af_alg_pull_tsgl(sk, ctx->used, NULL);
530466
sock_kzfree_s(sk, ctx->iv, ivlen);
531467
sock_kfree_s(sk, ctx, ctx->len);
532468
af_alg_release_parent(sk);

crypto/algif_skcipher.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
8989
* Create a per request TX SGL for this request which tracks the
9090
* SG entries from the global TX SGL.
9191
*/
92-
areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0);
92+
areq->tsgl_entries = af_alg_count_tsgl(sk, len);
9393
if (!areq->tsgl_entries)
9494
areq->tsgl_entries = 1;
9595
areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
@@ -100,7 +100,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
100100
goto free;
101101
}
102102
sg_init_table(areq->tsgl, areq->tsgl_entries);
103-
af_alg_pull_tsgl(sk, len, areq->tsgl, 0);
103+
af_alg_pull_tsgl(sk, len, areq->tsgl);
104104

105105
/* Initialize the crypto operation */
106106
skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm);
@@ -313,7 +313,7 @@ static void skcipher_sock_destruct(struct sock *sk)
313313
struct alg_sock *pask = alg_sk(psk);
314314
struct crypto_skcipher *tfm = pask->private;
315315

316-
af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
316+
af_alg_pull_tsgl(sk, ctx->used, NULL);
317317
sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm));
318318
sock_kfree_s(sk, ctx, ctx->len);
319319
af_alg_release_parent(sk);

include/crypto/if_alg.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,8 @@ static inline bool af_alg_readable(struct sock *sk)
225225
return PAGE_SIZE <= af_alg_rcvbuf(sk);
226226
}
227227

228-
unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset);
229-
void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
230-
size_t dst_offset);
228+
unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes);
229+
void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst);
231230
void af_alg_wmem_wakeup(struct sock *sk);
232231
int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min);
233232
int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,

0 commit comments

Comments
 (0)