diff mbox series

crypto: acomp: fix memory leaks caused by chained requests

Message ID 20250418100229.9868-1-dmantipov@yandex.ru
State New
Headers show
Series crypto: acomp: fix memory leaks caused by chained requests | expand

Commit Message

Dmitry Antipov April 18, 2025, 10:02 a.m. UTC
Running 6.15.0-rc2 with kmemleak enabled, I've noticed 45
memory leaks looks like the following:

unreferenced object 0xffff888114032a00 (size 256):
  comm "cryptomgr_test", pid 246, jiffies 4294668840
  hex dump (first 32 bytes):
    00 20 03 14 81 88 ff ff 00 da 02 14 81 88 ff ff  . ..............
    90 ca 54 9b ff ff ff ff c8 fb a6 00 00 c9 ff ff  ..T.............
  backtrace (crc cd58738d):
    __kmalloc_noprof+0x272/0x520
    alg_test_comp+0x74e/0x1b60
    alg_test+0x3f0/0xc40
    cryptomgr_test+0x47/0x80
    kthread+0x4e1/0x620
    ret_from_fork+0x37/0x70
    ret_from_fork_asm+0x1a/0x30

These leaks comes from 'test_acomp()' where an extra requests chained to
the head one (e.g. 'reqs[0]') are never freed. Fix this by unchaining
and freeing such an extra requests in 'acomp_request_free()'.

(I'm new to this subsystem and not sure about Fixes: tag BTW).

Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
---
 include/crypto/acompress.h | 28 ++++++++++++++++++++++------
 include/linux/crypto.h     |  5 +++++
 2 files changed, 27 insertions(+), 6 deletions(-)

Comments

Herbert Xu April 19, 2025, 3:37 a.m. UTC | #1
On Fri, Apr 18, 2025 at 01:02:29PM +0300, Dmitry Antipov wrote:
> Running 6.15.0-rc2 with kmemleak enabled, I've noticed 45
> memory leaks looks like the following:
> 
> unreferenced object 0xffff888114032a00 (size 256):
>   comm "cryptomgr_test", pid 246, jiffies 4294668840
>   hex dump (first 32 bytes):
>     00 20 03 14 81 88 ff ff 00 da 02 14 81 88 ff ff  . ..............
>     90 ca 54 9b ff ff ff ff c8 fb a6 00 00 c9 ff ff  ..T.............
>   backtrace (crc cd58738d):
>     __kmalloc_noprof+0x272/0x520
>     alg_test_comp+0x74e/0x1b60
>     alg_test+0x3f0/0xc40
>     cryptomgr_test+0x47/0x80
>     kthread+0x4e1/0x620
>     ret_from_fork+0x37/0x70
>     ret_from_fork_asm+0x1a/0x30
> 
> These leaks comes from 'test_acomp()' where an extra requests chained to
> the head one (e.g. 'reqs[0]') are never freed. Fix this by unchaining
> and freeing such an extra requests in 'acomp_request_free()'.
> 
> (I'm new to this subsystem and not sure about Fixes: tag BTW).
> 
> Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
> ---
>  include/crypto/acompress.h | 28 ++++++++++++++++++++++------
>  include/linux/crypto.h     |  5 +++++
>  2 files changed, 27 insertions(+), 6 deletions(-)

Thanks for the patch! I'll fix this by reverting the multibuffer
acomp tests:

https://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git/commit/?id=aece1cf146741761a1243746db5b72f5ece68290
diff mbox series

Patch

diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h
index c497c73baf13..d7de4cbccd60 100644
--- a/include/crypto/acompress.h
+++ b/include/crypto/acompress.h
@@ -310,6 +310,20 @@  static inline void *acomp_request_extra(struct acomp_req *req)
 	return (void *)((char *)req + len);
 }
 
+static inline void acomp_request_chain(struct acomp_req *req,
+				       struct acomp_req *head)
+{
+	crypto_request_chain(&req->base, &head->base);
+}
+
+static inline void acomp_request_unchain(struct acomp_req *req)
+{
+	crypto_request_unchain(&req->base);
+}
+
+#define acomp_request_for_each(this, tmp, head) \
+	list_for_each_entry_safe((this), (tmp), &(head)->base.list, base.list)
+
 /**
  * acomp_request_free() -- zeroize and free asynchronous (de)compression
  *			   request as well as the output buffer if allocated
@@ -319,8 +333,16 @@  static inline void *acomp_request_extra(struct acomp_req *req)
  */
 static inline void acomp_request_free(struct acomp_req *req)
 {
+	struct acomp_req *this, *tmp;
+
 	if (!req || (req->base.flags & CRYPTO_TFM_REQ_ON_STACK))
 		return;
+
+	acomp_request_for_each(this, tmp, req) {
+		acomp_request_unchain(this);
+		kfree_sensitive(this);
+	}
+
 	kfree_sensitive(req);
 }
 
@@ -558,12 +580,6 @@  static inline void acomp_request_set_dst_folio(struct acomp_req *req,
 	req->base.flags |= CRYPTO_ACOMP_REQ_DST_FOLIO;
 }
 
-static inline void acomp_request_chain(struct acomp_req *req,
-				       struct acomp_req *head)
-{
-	crypto_request_chain(&req->base, &head->base);
-}
-
 /**
  * crypto_acomp_compress() -- Invoke asynchronous compress operation
  *
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 1e3809d28abd..3e12bcee1497 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -486,6 +486,11 @@  static inline void crypto_request_chain(struct crypto_async_request *req,
 	list_add_tail(&req->list, &head->list);
 }
 
+static inline void crypto_request_unchain(struct crypto_async_request *req)
+{
+	list_del(&req->list);
+}
+
 static inline bool crypto_tfm_is_async(struct crypto_tfm *tfm)
 {
 	return tfm->__crt_alg->cra_flags & CRYPTO_ALG_ASYNC;