All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] erofs: cap LZMA stream pool size
@ 2026-07-14 11:47 Michael Bommarito
  2026-07-17  3:43 ` Gao Xiang
  0 siblings, 1 reply; 20+ messages in thread
From: Michael Bommarito @ 2026-07-14 11:47 UTC (permalink / raw)
  To: Gao Xiang, Chao Yu
  Cc: Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
	linux-erofs, linux-kernel, stable

fs/erofs/decompressor_lzma.c sizes the module-global MicroLZMA stream
pool from num_possible_cpus() when the lzma_streams module parameter is
unset, then z_erofs_load_lzma_config() preallocates one image-supplied
dictionary per stream, accepting dictionaries up to 8 MiB.  On high-CPU
systems, a small EROFS image can pin hundreds of MiB of vmalloc-backed
decoder state until the erofs module is unloaded.

Impact: an attacker-supplied EROFS image mounted by the system can pin up
to 8 MiB times the LZMA stream count of kernel vmalloc memory.

Bound the default stream count by a new
CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS option, default 16, so the
worst-case default preallocation is 128 MiB while preserving the existing
per-image dictionary limit.  An explicit lzma_streams module parameter is
still honoured as-is, so administrators who deliberately size the pool are
not affected.

Fixes: 622ceaddb764 ("erofs: lzma compression support")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
v3: rename the Kconfig option to EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS
    and only cap the default (num_possible_cpus); an explicit non-zero
    lzma_streams module parameter is now honoured unchanged.  Simplified
    the Kconfig help text and dropped the in-code comment, per Gao
    Xiang's review.
v2: https://lore.kernel.org/linux-erofs/20260711143419.2762894-1-michael.bommarito@gmail.com/

Evidence: the stock code sets the stream count to num_possible_cpus() when
lzma_streams is unset, and z_erofs_load_lzma_config() then preallocates one
image-supplied dictionary (up to Z_EROFS_LZMA_MAX_DICT_SIZE, 8 MiB) per
stream, so on a host with many CPUs a single small mounted image reserves
num_possible_cpus() x up-to-8 MiB of vmalloc decoder state until the module
is unloaded.  With this patch an unset lzma_streams caps the default at
CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS (16, i.e. 128 MiB worst case),
while an explicit non-zero lzma_streams= is left unbounded.  Built with W=1,
no new warnings; boots and mounts an LZMA image with the capped default and
with lzma_streams= overriding it.

 fs/erofs/Kconfig             | 14 ++++++++++++++
 fs/erofs/decompressor_lzma.c |  3 ++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig
index 4789b1077d8ce..8948cb6314e07 100644
--- a/fs/erofs/Kconfig
+++ b/fs/erofs/Kconfig
@@ -131,6 +131,20 @@ config EROFS_FS_ZIP_LZMA
 
 	  Say N if you want to disable LZMA compression support.
 
+config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS
+	int "EROFS LZMA default maximum decompression streams"
+	depends on EROFS_FS_ZIP_LZMA
+	range 1 1024
+	default 16
+	help
+	  By default EROFS allocates one LZMA decompression stream per CPU.
+	  Each stream can hold a dictionary of up to 8 MiB taken from the
+	  mounted image, so on systems with many CPUs this can reserve a lot
+	  of memory.  This caps the default; the lzma_streams module parameter
+	  still overrides it.
+
+	  If unsure, keep the default of 16.
+
 config EROFS_FS_ZIP_DEFLATE
 	bool "EROFS DEFLATE compressed data support"
 	depends on EROFS_FS_ZIP
diff --git a/fs/erofs/decompressor_lzma.c b/fs/erofs/decompressor_lzma.c
index f6692d0f2f04d..6b0cdb446c6ad 100644
--- a/fs/erofs/decompressor_lzma.c
+++ b/fs/erofs/decompressor_lzma.c
@@ -51,7 +51,8 @@ static int __init z_erofs_lzma_init(void)
 
 	/* by default, use # of possible CPUs instead */
 	if (!z_erofs_lzma_nstrms)
-		z_erofs_lzma_nstrms = num_possible_cpus();
+		z_erofs_lzma_nstrms = min_t(unsigned int, num_possible_cpus(),
+				CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS);
 
 	for (i = 0; i < z_erofs_lzma_nstrms; ++i) {
 		struct z_erofs_lzma *strm = kzalloc_obj(*strm);
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-08-12 14:26 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-14 11:47 [PATCH v3] erofs: cap LZMA stream pool size Michael Bommarito
2026-07-17  3:43 ` Gao Xiang
2026-07-21  3:44   ` Gao Xiang
2026-07-28  3:46     ` SJ Park
2026-07-28  6:31       ` Gao Xiang
2026-07-28  6:54         ` SJ Park
2026-08-03  8:09           ` Geert Uytterhoeven
2026-08-03  9:12             ` Uwe Kleine-König
2026-08-11 19:27               ` Geert Uytterhoeven
2026-08-11 19:35                 ` Guenter Roeck
2026-08-11 19:37                   ` Michael Bommarito
2026-08-11 23:36                     ` Gao Xiang
2026-08-12  9:30                       ` Geert Uytterhoeven
2026-08-12 10:54                         ` Gao Xiang
2026-08-12 11:28                           ` Geert Uytterhoeven
2026-08-12 13:11                             ` [PATCH] erofs: fix EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS on some UP platforms Gao Xiang
2026-08-12 13:34                               ` Geert Uytterhoeven
2026-08-12 14:13                                 ` Gao Xiang
2026-08-12 14:21                               ` SJ Park
2026-08-12 14:25                           ` [PATCH v3] erofs: cap LZMA stream pool size Guenter Roeck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.