[PATCH v3] tmpfs: fix unicode_map leaks in casefold option handling
From: Kazuki Hanai
Date: Fri Oct 02 2026 - 04:13:31 EST
shmem_parse_opt_casefold() stores the unicode_map returned by
utf8_load() in ctx->encoding. A filesystem context can receive the
casefold parameter more than once, and a second successful parse
overwrites the stored map without releasing it.
The map is also leaked when an unmounted filesystem context is freed.
This includes the temporary context used for remount, because
shmem_reconfigure() does not take ownership of ctx->encoding.
Reject a second casefold setting, clear ctx->encoding after transferring
ownership to the superblock, and release any remaining map from
shmem_free_fc().
An unprivileged user can repeatedly create tmpfs filesystem contexts,
set the casefold parameter, and close them from a user namespace. This
causes unbounded kernel memory consumption and can result in a local
denial of service.
Fixes: 58e55efd6c72 ("tmpfs: Add casefold lookup support")
Cc: stable@xxxxxxxxxxxxxxx
Suggested-by: Gabriel Krisman Bertazi <gabriel@xxxxxxxxxx>
Signed-off-by: Kazuki Hanai <hnkz.64@xxxxxxxxx>
---
Changes in v3:
- Reject a second casefold option instead of unloading and replacing the
first map, as suggested by Gabriel.
- Reword the commit message to describe the remount and close paths.
Changes in v2:
- Keep Fixes, Cc, and Signed-off-by in a single trailer block.
mm/shmem.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/mm/shmem.c b/mm/shmem.c
index 848316eaa7f4fb..1bd004c3dde20b 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -4509,6 +4509,9 @@ static int shmem_parse_opt_casefold(struct fs_context *fc, struct fs_parameter *
struct unicode_map *encoding;
char *version_str = param->string + 5;
+ if (ctx->encoding)
+ return invalfc(fc, "casefold parameter cannot be specified twice\n");
+
if (!latest_version) {
if (strncmp(param->string, "utf8-", 5))
return invalfc(fc, "Only UTF-8 encodings are supported "
@@ -4998,6 +5001,7 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
if (ctx->encoding) {
sb->s_encoding = ctx->encoding;
+ ctx->encoding = NULL;
set_default_d_op(sb, &shmem_ci_dentry_ops);
if (ctx->strict_encoding)
sb->s_encoding_flags = SB_ENC_STRICT_MODE_FL;
@@ -5095,6 +5099,9 @@ static void shmem_free_fc(struct fs_context *fc)
struct shmem_options *ctx = fc->fs_private;
if (ctx) {
+#if IS_ENABLED(CONFIG_UNICODE)
+ utf8_unload(ctx->encoding);
+#endif
mpol_put(ctx->mpol);
kfree(ctx);
}
--
2.53.0