From: "Jianzhou Zhao" <luckd0g@163.com>
To: urezki@gmail.com, akpm@linux-foundation.org
Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org
Subject: KASAN: vmalloc-out-of-bounds Write in vfree_atomic
Date: Wed, 11 Mar 2026 16:49:23 +0800 (CST) [thread overview]
Message-ID: <57fac928.7af6.19cdc162036.Coremail.luckd0g@163.com> (raw)
To: linkinjeon@kernel.org, sj1557.seo@samsung.com
Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [BUG] exfat: KASAN: vmalloc-out-of-bounds Write in delayed_free due to double-free of vol_utbl
Dear exFAT Maintainers,
Our custom fuzzing tool, RacePilot, has detected a vmalloc-out-of-bounds write inside the `delayed_free` function. The underlying issue is a double-free vulnerability regarding the upcase table (`vol_utbl`).
### Call Trace:
```
BUG: KASAN: vmalloc-out-of-bounds in llist_add_batch+0x15f/0x180 lib/llist.c:32
Write of size 8 at addr ffffc90005319000 by task syz.4.373/14262
Call Trace:
<IRQ>
...
kasan_report+0x96/0xd0 mm/kasan/report.c:634
llist_add_batch+0x15f/0x180 lib/llist.c:32
llist_add include/linux/llist.h:248 [inline]
vfree_atomic+0x5e/0xe0 mm/vmalloc.c:3326
vfree+0x708/0x8a0 mm/vmalloc.c:3353
delayed_free+0x49/0xb0 fs/exfat/super.c:799
rcu_do_batch kernel/rcu/tree.c:2568 [inline]
...
```
### Underlying Root Cause:
The issue occurs when `exfat_create_upcase_table()` fails to load an upcase table and subsequently fails to load the default fallback due to memory exhaustion (-ENOMEM), causing `sbi->vol_utbl` to be double-freed.
1. During `exfat_create_upcase_table()`, if `exfat_load_upcase_table()` returns an error other than `-EIO` (e.g. `-EINVAL` from a checksum mismatch), the code triggers `exfat_free_upcase_table()` to free the invalid table before jumping to `load_default`.
2. Inside `exfat_free_upcase_table()`, `kvfree(sbi->vol_utbl)` is executed, but `sbi->vol_utbl` is **not set to NULL**.
3. In `load_default:`, the execution calls `exfat_load_default_upcase_table(sb)`.
4. If the system is under memory pressure, `kvcalloc()` inside the default loader fails and returns `-ENOMEM`. Because of this failure, `sbi->vol_utbl` is not overwritten with a new pointer, leaving it holding the previously freed vmalloc address.
5. The `-ENOMEM` failure propagates up, aborting the filesystem mount. The VFS superblock teardown eventually processes to `exfat_kill_sb()`, queuing the RCU callback `delayed_free()`.
6. When `delayed_free()` asynchronously runs, it again calls `exfat_free_upcase_table(sbi)`.
7. `kvfree()` is called for a second time on the old `sbi->vol_utbl`, constituting a double free.
8. Because `delayed_free` executes in a softirq context, `kvfree()` delegates the cleanup to `vfree_atomic()`. `vfree_atomic` casts the virtual address to an `llist_node` and writes its `next` pointer. KASAN catches this illicit write operation on previously freed, unmapped vmalloc memory, emitting the `vmalloc-out-of-bounds` exception.
### Key Code Snippets:
In `fs/exfat/nls.c`, `exfat_create_upcase_table()`:
```c
ret = exfat_load_upcase_table(sb, sector, num_sectors, ...);
brelse(bh);
if (ret && ret != -EIO) {
/* free memory from exfat_load_upcase_table call */
exfat_free_upcase_table(sbi); // [1] Frees ->vol_utbl but leaves a dangling pointer
goto load_default;
}
...
load_default:
/* load default upcase table */
return exfat_load_default_upcase_table(sb); // [2] Fails on kvcalloc and returns -ENOMEM
```
In `fs/exfat/super.c`, inside `delayed_free()`:
```c
static void delayed_free(struct rcu_head *p)
{
...
exfat_free_upcase_table(sbi); // [3] Second invocation leads to double free UAF
exfat_free_sbi(sbi);
}
```
### Proposed Fix:
The solution is natively simple: nullify `sbi->vol_utbl` directly inside `exfat_free_upcase_table()` after freeing it. This safely converts the secondary asynchronous `kvfree` into a no-op.
```c
void exfat_free_upcase_table(struct exfat_sb_info *sbi)
{
kvfree(sbi->vol_utbl);
+ sbi->vol_utbl = NULL;
}
```
Best regards,
The RacePilot Team
next reply other threads:[~2026-03-11 8:49 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-11 8:49 Jianzhou Zhao [this message]
2026-03-11 10:48 ` Namjae Jeon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=57fac928.7af6.19cdc162036.Coremail.luckd0g@163.com \
--to=luckd0g@163.com \
--cc=akpm@linux-foundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=urezki@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox