public inbox for linux-mm@kvack.org
 help / color / mirror / Atom feed
* KASAN: vmalloc-out-of-bounds Write in vfree_atomic
@ 2026-03-11  8:49 Jianzhou Zhao
  2026-03-11 10:48 ` Namjae Jeon
  0 siblings, 1 reply; 2+ messages in thread
From: Jianzhou Zhao @ 2026-03-11  8:49 UTC (permalink / raw)
  To: urezki, akpm; +Cc: linux-mm, linux-kernel



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

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

* Re: KASAN: vmalloc-out-of-bounds Write in vfree_atomic
  2026-03-11  8:49 KASAN: vmalloc-out-of-bounds Write in vfree_atomic Jianzhou Zhao
@ 2026-03-11 10:48 ` Namjae Jeon
  0 siblings, 0 replies; 2+ messages in thread
From: Namjae Jeon @ 2026-03-11 10:48 UTC (permalink / raw)
  To: Jianzhou Zhao; +Cc: urezki, akpm, linux-mm, linux-kernel

> ### 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;
>  }
> ```
It was already fixed back in early 2025 with commit 1f3d9724e16d
('exfat: fix double free in delayed_free').


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

end of thread, other threads:[~2026-03-11 10:48 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-11  8:49 KASAN: vmalloc-out-of-bounds Write in vfree_atomic Jianzhou Zhao
2026-03-11 10:48 ` Namjae Jeon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox