fs/exfat/super.c | 4 ++++ 1 file changed, 4 insertions(+)
exfat_alloc_inode() does not initialize the cache_lru list head of
struct exfat_inode_info.
If an inode is evicted before its cache structures are properly
initialized (e.g., during a forced unmount), the cleanup
path in __exfat_cache_inval_inode() may observe an uninitialized
list head.
The check:
while (!list_empty(&ei->cache_lru))
may incorrectly succeed when stale pointers remain from a reused
slab object. Subsequent list traversal can then operate on invalid
entries, potentially leading to a NULL pointer dereference or
memory corruption.
Initialize cache_lru, cache_lru_lock, nr_caches, and cache_valid_id
in exfat_alloc_inode() to ensure a well-defined state at allocation
time.
Signed-off-by: Yang Wen <anmuxixixi@gmail.com>
---
fs/exfat/super.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index 83396fd265cd..0c4a22b8d5fa 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -195,6 +195,10 @@ static struct inode *exfat_alloc_inode(struct super_block *sb)
if (!ei)
return NULL;
+ spin_lock_init(&ei->cache_lru_lock);
+ ei->nr_caches = 0;
+ ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
+ INIT_LIST_HEAD(&ei->cache_lru);
init_rwsem(&ei->truncate_lock);
return &ei->vfs_inode;
}
--
2.43.0
> diff --git a/fs/exfat/super.c b/fs/exfat/super.c > index 83396fd265cd..0c4a22b8d5fa 100644 > --- a/fs/exfat/super.c > +++ b/fs/exfat/super.c > @@ -195,6 +195,10 @@ static struct inode *exfat_alloc_inode(struct super_block *sb) > if (!ei) > return NULL; > > + spin_lock_init(&ei->cache_lru_lock); > + ei->nr_caches = 0; > + ei->cache_valid_id = EXFAT_CACHE_VALID + 1; > + INIT_LIST_HEAD(&ei->cache_lru); These fields are already initialized in exfat_inode_init_once(). Please check exfat_inode_init_once(). Thanks.
On Mon, 2 Mar 2026 18:58:41 Namjae Jeon <linkinjeon@kernel.org> wrote: > >diff --git a/fs/exfat/super.c b/fs/exfat/super.c > >index 83396fd265cd..0c4a22b8d5fa 100644 > >--- a/fs/exfat/super.c > >+++ b/fs/exfat/super.c > >@@ -195,6 +195,10 @@ static struct inode *exfat_alloc_inode(struct super_block *sb) > > if (!ei) > > return NULL; > > > >+ spin_lock_init(&ei->cache_lru_lock); > >+ ei->nr_caches = 0; > >+ ei->cache_valid_id = EXFAT_CACHE_VALID + 1; > >+ INIT_LIST_HEAD(&ei->cache_lru); > These fields are already initialized in exfat_inode_init_once(). > Please check exfat_inode_init_once(). > Thanks. Thanks for your replay. While it's true that exfat_inode_init_once() initializes these fields, that constructor is only invoked when the slab object is first created. In the case of inode reuse (when an object is freed to the slab cache and subsequently re-allocated), the fields inherit stale values from the previous user of that memory block. If an eviction occurs before these fields are re-initialized by the new owner, __exfat_cache_inval_inode() sees a non-empty list due to stale pointers, leading to a NULL pointer dereference. We have recently observed kernel panics on mobile devices, which were traced back to a NULL pointer dereference in list_del_init() within __exfat_cache_inval_inode(). Thanks.
On Mon, Mar 2, 2026 at 11:10 PM Yang Wen <anmuxixixi@gmail.com> wrote: > > On Mon, 2 Mar 2026 18:58:41 Namjae Jeon <linkinjeon@kernel.org> wrote: > > > >diff --git a/fs/exfat/super.c b/fs/exfat/super.c > > >index 83396fd265cd..0c4a22b8d5fa 100644 > > >--- a/fs/exfat/super.c > > >+++ b/fs/exfat/super.c > > >@@ -195,6 +195,10 @@ static struct inode *exfat_alloc_inode(struct super_block *sb) > > > if (!ei) > > > return NULL; > > > > > >+ spin_lock_init(&ei->cache_lru_lock); > > >+ ei->nr_caches = 0; > > >+ ei->cache_valid_id = EXFAT_CACHE_VALID + 1; > > >+ INIT_LIST_HEAD(&ei->cache_lru); > > These fields are already initialized in exfat_inode_init_once(). > > Please check exfat_inode_init_once(). > > Thanks. > > Thanks for your replay. While it's true that exfat_inode_init_once() > initializes these fields, that constructor is only invoked when the > slab object is first created. > > In the case of inode reuse (when an object is freed to the slab cache > and subsequently re-allocated), the fields inherit stale values from > the previous user of that memory block. If an eviction occurs before > these fields are re-initialized by the new owner, > __exfat_cache_inval_inode() sees a non-empty list due to stale > pointers, leading to a NULL pointer dereference. > > We have recently observed kernel panics on mobile devices, which were > traced back to a NULL pointer dereference in list_del_init() > within __exfat_cache_inval_inode(). Okay, Do we need to keep the duplicate initialization code in exfat_inode_init_once()? Thanks.
© 2016 - 2026 Red Hat, Inc.