Re: ntfs3: Use after free race condition in ntfs_read_folio()?
Dirk Behme <[email protected]> Wed, 27 May 2026 12:37:48 +0200
| Newsgroups | dev.linux.lists.ntfs3 |
|---|---|
| Message-ID | <[email protected]> |
On 27.05.2026 06:34, Dirk Behme wrote:
> Hi,
>
> on a custom ARM64 board with kernel 6.1.157 we got a report about a data
> abort Oops [1] in ntfs_read_folio() [2]. The disassembly is [3].
>
> Analysing this the failing instruction is
>
> 385f82e8 ldurb w8, [x23, #-8]
>
> with x23: ffff8d623ef35800 - 8 matching the fault address ffff8d623ef357f8.
>
> Matching this to the C code we think the compiler summarises
>
> struct ntfs_inode *ni = ntfs_i(inode);
> if (is_resident(ni)) {
>
> to one assembly instruction to access the ni_flags in struct ntfs_inode
> via the inode [4].
>
> Getting a data abort trying to access the ni_flags, we assume that the
> whole struct ntfs_inode has been freed, already. While missing to
> reset / clear some reference to it. What in sum looks like a use after
> free race condition accessing struct ntfs_inode in ntfs_read_folio().
>
> We have searched for something obvious in more recent commits but
> couldn't find anything what looks related. Have we missed anything?
>
> What do you think? Any idea?
>
> Thanks
>
> Dirk
>
> [1]
>
> Unable to handle kernel paging request at virtual address ffff8d623ef357f8
> Mem abort info:
> ESR = 0x0000000096000004
> EC = 0x25: DABT (current EL), IL = 32 bits
> SET = 0, FnV = 0
> EA = 0, S1PTW = 0
> FSC = 0x04: level 0 translation fault
> Data abort info:
> ISV = 0, ISS = 0x00000004
> CM = 0, WnR = 0
> [ffff8d623ef357f8] address between user and kernel address ranges
> Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP
> Modules linked in: ... ntfs3 ...
> CPU: 3 PID: 9611 Comm: binder:529_A Tainted: G O 6.1.157 #1
> Hardware name: ARM64 custom board
> pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> pc : ntfs_read_folio+0x24/0xe0 [ntfs3]
> lr : filemap_read_folio+0x6c/0x15c
> sp : ffffffc01c05bad0
> x29: ffffffc01c05bad0 x28: 00000000fffffa00 x27: 0000000000080001
> x26: 00000000ffffffff x25: ff00000000000000 x24: ffffff8d623ef4e8
> x23: ffff8d623ef35800 x22: 0000000000000000 x21: ffffffc001591414
> x20: fffffffe378c42c0 x19: fffffffe378c42c0 x18: ffffffc0109a0080
> x17: 000000001b98ee9a x16: 000000001b98ee9a x15: ffffffc00158ed90
> x14: 0000000000000007 x13: 000000000001d3a2 x12: ffffffce57fbe000
> x11: 0000000000000001 x10: 0000000000000001 x9 : 0000000000000100
> x8 : ffffff8d623ef4e7 x7 : 0000000000000000 x6 : 0000000000000000
> x5 : ffffff8ca937808c x4 : ffffffc01c05bb50 x3 : 0000000006100cca
> x2 : fffffffe378c42c0 x1 : fffffffe378c42c0 x0 : 0000000000000000
> Call trace:
> ntfs_read_folio+0x24/0xe0 [ntfs3]
> filemap_read_folio+0x6c/0x15c
> do_read_cache_folio+0x144/0x338
> read_cache_page+0x1c/0x58
> ntfs_fill_super+0xde8/0xf20 [ntfs3]
> get_tree_bdev+0x1c4/0x258
> ntfs_fs_get_tree+0x18/0x28 [ntfs3]
> vfs_get_tree+0x48/0xfc
> do_new_mount+0x154/0x36c
> path_mount+0x270/0x4e4
> __arm64_sys_mount+0x1b4/0x3dc
> invoke_syscall+0x58/0x118
> el0_svc_common+0xb4/0xf4
> do_el0_svc+0x24/0x80
> el0_svc+0x2c/0x90
> el0t_64_sync_handler+0x68/0xb4
> el0t_64_sync+0x1a4/0x1a8
> Code: 910003fd f9400c28 aa0103f3 f9400117 (385f82e8)
> ---[ end trace 0000000000000000 ]---
> Kernel panic - not syncing: Oops: Fatal exception
> SMP: stopping secondary CPUs
>
> [2]
>
> static int ntfs_read_folio(struct file *file, struct folio *folio)
> {
> struct page *page = &folio->page;
> int err;
> struct address_space *mapping = page->mapping;
> struct inode *inode = mapping->host;
> struct ntfs_inode *ni = ntfs_i(inode);
>
> if (is_resident(ni)) {
> ni_lock(ni);
> err = attr_data_read_resident(ni, page);
> ni_unlock(ni);
> if (err != E_NTFS_NONRESIDENT) {
> unlock_page(page);
> return err;
> }
> }
>
> if (is_compressed(ni)) {
> ni_lock(ni);
> err = ni_readpage_cmpr(ni, page);
> ni_unlock(ni);
> return err;
> }
>
> /* Normal + sparse files. */
> return mpage_read_folio(folio, ntfs_get_block);
> }
>
> [3]
>
> 000000000001e934 <ntfs_read_folio>:
> 1e934: d503233f paciasp
> 1e938: a9bc7bfd stp x29, x30, [sp, #-64]!
> 1e93c: f9000bf7 str x23, [sp, #16]
> 1e940: a90257f6 stp x22, x21, [sp, #32]
> 1e944: a9034ff4 stp x20, x19, [sp, #48]
> 1e948: 910003fd mov x29, sp
> 1e94c: f9400c28 ldr x8, [x1, #24]
> 1e950: aa0103f3 mov x19, x1
> 1e954: f9400117 ldr x23, [x8]
> 1e958: 385f82e8 ldurb w8, [x23, #-8]
>
> [4]
>
> struct ntfs_inode {
> ....
>
> size_t ni_flags; // NI_FLAG_XXX
>
> struct inode vfs_inode;
> };
I just learned that this is the same topic as the previously sent
https://lore.kernel.org/ntfs3/PAVPR10MB71635C5EF1E4FED2FF9C8107B60A2@PAVPR10MB7163.EURPRD10.PROD.OUTLOOK.COM/
Sorry for sending it twice!
An additional observation is
x8 : ffffff8d623ef4e7
being unaligned. Assuming that this is
struct address_space *mapping = page->mapping
we wonder if we are talking about a broken *mapping instead of a use
after free we assumed initially above.
Sorry again for sending two times,
Dirk