* [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info @ 2026-09-09 2:39 ` Lucas Jeffrey 0 siblings, 0 replies; 12+ messages in thread From: Lucas Jeffrey @ 2026-09-09 2:39 UTC (permalink / raw) To: dwmw2 Cc: richard, linux-mtd, linux-kernel, Lucas Jeffrey, syzbot+3a8099322b09d8d073d1 When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it can retain stale values from its previous use. If the new jffs2_inode_info object allocated retains an old reference to a freed inocache, the function jffs2_new_inode may crash if either jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because when calling iput() with the inode it will eventually attempt to free again the inocache. Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> --- fs/jffs2/os-linux.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 86ab014a349c..40f17218a276 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { f->highest_version = 0; f->fragtree = RB_ROOT; + f->inocache = NULL; f->metadata = NULL; f->dents = NULL; f->target = NULL; -- 2.43.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info @ 2026-09-09 2:39 ` Lucas Jeffrey 0 siblings, 0 replies; 12+ messages in thread From: Lucas Jeffrey @ 2026-09-09 2:39 UTC (permalink / raw) To: dwmw2 Cc: richard, linux-mtd, linux-kernel, Lucas Jeffrey, syzbot+3a8099322b09d8d073d1 When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it can retain stale values from its previous use. If the new jffs2_inode_info object allocated retains an old reference to a freed inocache, the function jffs2_new_inode may crash if either jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because when calling iput() with the inode it will eventually attempt to free again the inocache. Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> --- fs/jffs2/os-linux.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 86ab014a349c..40f17218a276 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { f->highest_version = 0; f->fragtree = RB_ROOT; + f->inocache = NULL; f->metadata = NULL; f->dents = NULL; f->target = NULL; -- 2.43.0 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info 2026-09-09 2:39 ` Lucas Jeffrey @ 2026-09-09 2:54 ` sashiko-bot -1 siblings, 0 replies; 12+ messages in thread From: sashiko-bot @ 2026-09-09 2:54 UTC (permalink / raw) To: Lucas Jeffrey, dwmw2 Cc: richard, linux-mtd, linux-kernel, syzbot+3a8099322b09d8d073d1 Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Pre-existing issues: - [Critical] Double free of `f->target` on early VFS failure paths due to uninitialized slab memory. -- commit 9fd2012cfec1b8d15df193fea97deabda99aa5e5 Author: Lucas Jeffrey <luquijeffrey@gmail.com> jffs: initialize inocache to NULL when initializing a jffs2_inode_info When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it can retain stale values from its previous use. If the new jffs2_inode_info object allocated retains an old reference to a freed inocache, the function jffs2_new_inode may crash if either jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because when calling iput() with the inode it will eventually attempt to free again the inocache. Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> > diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h > index 86ab014a349c5..40f17218a276b 100644 > --- a/fs/jffs2/os-linux.h > +++ b/fs/jffs2/os-linux.h > @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) > { > f->highest_version = 0; > f->fragtree = RB_ROOT; > + f->inocache = NULL; > f->metadata = NULL; > f->dents = NULL; > f->target = NULL; [Severity: Critical] This isn't a bug introduced by this patch, but doesn't f->target suffer from a similar issue due to uninitialized slab memory on early VFS failure paths? When the VFS allocates a new inode via jffs2_alloc_inode() in fs/jffs2/super.c, the object is returned from the SLAB cache without __GFP_ZERO. It retains stale values from its previous lifecycle, including a dangling pointer in f->target, because jffs2_free_inode() frees f->target but does not nullify it. JFFS2 defers initializing f->target = NULL to jffs2_init_inode_info(), which is called after VFS initialization completes. If the VFS fails early (e.g., inode_init_always() fails due to an LSM memory allocation, or iget_locked() in fs/inode.c encounters a hash collision race and drops the newly allocated inode), the VFS destroys the inode via jffs2_free_inode() before JFFS2 ever initializes it. This causes a double free when kfree(f->target) executes again on the dangling pointer: fs/jffs2/super.c:jffs2_free_inode() { ... kfree(f->target); kmem_cache_free(jffs2_inode_cachep, f); } Userspace can reliably trigger the iget_locked() hash collision race by performing concurrent lookups (e.g., stat() or open()) on the same non-resident inode: fs/inode.c:iget_locked() { ... if (unlikely(test_bit(__I_NEW, &inode->i_state))) { /* Uhhuh, somebody else created the same inode under us... */ spin_unlock(&inode_hash_lock); destroy_inode(inode); ... } Would it be safer to zero these fields in jffs2_alloc_inode() or ensure jffs2_free_inode() nullifies them before returning the object to the slab cache? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260909023955.1642244-1-luquijeffrey@gmail.com?part=1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info @ 2026-09-09 2:54 ` sashiko-bot 0 siblings, 0 replies; 12+ messages in thread From: sashiko-bot @ 2026-09-09 2:54 UTC (permalink / raw) To: Lucas Jeffrey, dwmw2 Cc: richard, linux-mtd, linux-kernel, syzbot+3a8099322b09d8d073d1 Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Pre-existing issues: - [Critical] Double free of `f->target` on early VFS failure paths due to uninitialized slab memory. -- commit 9fd2012cfec1b8d15df193fea97deabda99aa5e5 Author: Lucas Jeffrey <luquijeffrey@gmail.com> jffs: initialize inocache to NULL when initializing a jffs2_inode_info When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it can retain stale values from its previous use. If the new jffs2_inode_info object allocated retains an old reference to a freed inocache, the function jffs2_new_inode may crash if either jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because when calling iput() with the inode it will eventually attempt to free again the inocache. Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> > diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h > index 86ab014a349c5..40f17218a276b 100644 > --- a/fs/jffs2/os-linux.h > +++ b/fs/jffs2/os-linux.h > @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) > { > f->highest_version = 0; > f->fragtree = RB_ROOT; > + f->inocache = NULL; > f->metadata = NULL; > f->dents = NULL; > f->target = NULL; [Severity: Critical] This isn't a bug introduced by this patch, but doesn't f->target suffer from a similar issue due to uninitialized slab memory on early VFS failure paths? When the VFS allocates a new inode via jffs2_alloc_inode() in fs/jffs2/super.c, the object is returned from the SLAB cache without __GFP_ZERO. It retains stale values from its previous lifecycle, including a dangling pointer in f->target, because jffs2_free_inode() frees f->target but does not nullify it. JFFS2 defers initializing f->target = NULL to jffs2_init_inode_info(), which is called after VFS initialization completes. If the VFS fails early (e.g., inode_init_always() fails due to an LSM memory allocation, or iget_locked() in fs/inode.c encounters a hash collision race and drops the newly allocated inode), the VFS destroys the inode via jffs2_free_inode() before JFFS2 ever initializes it. This causes a double free when kfree(f->target) executes again on the dangling pointer: fs/jffs2/super.c:jffs2_free_inode() { ... kfree(f->target); kmem_cache_free(jffs2_inode_cachep, f); } Userspace can reliably trigger the iget_locked() hash collision race by performing concurrent lookups (e.g., stat() or open()) on the same non-resident inode: fs/inode.c:iget_locked() { ... if (unlikely(test_bit(__I_NEW, &inode->i_state))) { /* Uhhuh, somebody else created the same inode under us... */ spin_unlock(&inode_hash_lock); destroy_inode(inode); ... } Would it be safer to zero these fields in jffs2_alloc_inode() or ensure jffs2_free_inode() nullifies them before returning the object to the slab cache? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260909023955.1642244-1-luquijeffrey@gmail.com?part=1 ^ permalink raw reply [flat|nested] 12+ messages in thread
* AW: [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info 2026-09-09 2:54 ` sashiko-bot @ 2026-09-09 5:57 ` Richard Weinberger -1 siblings, 0 replies; 12+ messages in thread From: Richard Weinberger @ 2026-09-09 5:57 UTC (permalink / raw) To: sashiko-reviews, Lucas Jeffrey, dwmw2 Cc: linux-mtd, linux-kernel, syzbot+3a8099322b09d8d073d1 Lucas, Am Wed, Sep 9, 2026, 04:54 schrieb sashiko-bot@kernel.org: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > > Pre-existing issues: > - [Critical] Double free of `f->target` on early VFS failure paths due to uninitialized slab memory. > -- > > commit 9fd2012cfec1b8d15df193fea97deabda99aa5e5 > Author: Lucas Jeffrey <luquijeffrey@gmail.com> > > jffs: initialize inocache to NULL when initializing a jffs2_inode_info > > When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it > can retain stale values from its previous use. > > If the new jffs2_inode_info object allocated retains an old reference to a > freed inocache, the function jffs2_new_inode may crash if either > jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because > when calling iput() with the inode it will eventually attempt to free again > the inocache. > > Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com > Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 > Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> > > > diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h > > index 86ab014a349c5..40f17218a276b 100644 > > --- a/fs/jffs2/os-linux.h > > +++ b/fs/jffs2/os-linux.h > > @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) > > { > > f->highest_version = 0; > > f->fragtree = RB_ROOT; > > + f->inocache = NULL; > > f->metadata = NULL; > > f->dents = NULL; > > f->target = NULL; > > [Severity: Critical] > This isn't a bug introduced by this patch, but doesn't f->target suffer from > a similar issue due to uninitialized slab memory on early VFS failure paths? > > When the VFS allocates a new inode via jffs2_alloc_inode() in > fs/jffs2/super.c, the object is returned from the SLAB cache without > __GFP_ZERO. It retains stale values from its previous lifecycle, including > a dangling pointer in f->target, because jffs2_free_inode() frees f->target > but does not nullify it. > > JFFS2 defers initializing f->target = NULL to jffs2_init_inode_info(), which > is called after VFS initialization completes. If the VFS fails early (e.g., > inode_init_always() fails due to an LSM memory allocation, or iget_locked() > in fs/inode.c encounters a hash collision race and drops the newly allocated > inode), the VFS destroys the inode via jffs2_free_inode() before JFFS2 ever > initializes it. > > This causes a double free when kfree(f->target) executes again on the > dangling pointer: > > fs/jffs2/super.c:jffs2_free_inode() { > ... > kfree(f->target); > kmem_cache_free(jffs2_inode_cachep, f); > } > > Userspace can reliably trigger the iget_locked() hash collision race by > performing concurrent lookups (e.g., stat() or open()) on the same > non-resident inode: > > fs/inode.c:iget_locked() { > ... > if (unlikely(test_bit(__I_NEW, &inode->i_state))) { > /* Uhhuh, somebody else created the same inode under us... */ > spin_unlock(&inode_hash_lock); > destroy_inode(inode); > ... > } > > Would it be safer to zero these fields in jffs2_alloc_inode() or ensure > jffs2_free_inode() nullifies them before returning the object to the slab > cache? I think this is a legit bug pointed out by Sashiko. Do you want to double check and (if needed) fix it? Thanks, //richard ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 12+ messages in thread
* AW: [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info @ 2026-09-09 5:57 ` Richard Weinberger 0 siblings, 0 replies; 12+ messages in thread From: Richard Weinberger @ 2026-09-09 5:57 UTC (permalink / raw) To: sashiko-reviews, Lucas Jeffrey, dwmw2 Cc: linux-mtd, linux-kernel, syzbot+3a8099322b09d8d073d1 Lucas, Am Wed, Sep 9, 2026, 04:54 schrieb sashiko-bot@kernel.org: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > > Pre-existing issues: > - [Critical] Double free of `f->target` on early VFS failure paths due to uninitialized slab memory. > -- > > commit 9fd2012cfec1b8d15df193fea97deabda99aa5e5 > Author: Lucas Jeffrey <luquijeffrey@gmail.com> > > jffs: initialize inocache to NULL when initializing a jffs2_inode_info > > When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it > can retain stale values from its previous use. > > If the new jffs2_inode_info object allocated retains an old reference to a > freed inocache, the function jffs2_new_inode may crash if either > jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because > when calling iput() with the inode it will eventually attempt to free again > the inocache. > > Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com > Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 > Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> > > > diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h > > index 86ab014a349c5..40f17218a276b 100644 > > --- a/fs/jffs2/os-linux.h > > +++ b/fs/jffs2/os-linux.h > > @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) > > { > > f->highest_version = 0; > > f->fragtree = RB_ROOT; > > + f->inocache = NULL; > > f->metadata = NULL; > > f->dents = NULL; > > f->target = NULL; > > [Severity: Critical] > This isn't a bug introduced by this patch, but doesn't f->target suffer from > a similar issue due to uninitialized slab memory on early VFS failure paths? > > When the VFS allocates a new inode via jffs2_alloc_inode() in > fs/jffs2/super.c, the object is returned from the SLAB cache without > __GFP_ZERO. It retains stale values from its previous lifecycle, including > a dangling pointer in f->target, because jffs2_free_inode() frees f->target > but does not nullify it. > > JFFS2 defers initializing f->target = NULL to jffs2_init_inode_info(), which > is called after VFS initialization completes. If the VFS fails early (e.g., > inode_init_always() fails due to an LSM memory allocation, or iget_locked() > in fs/inode.c encounters a hash collision race and drops the newly allocated > inode), the VFS destroys the inode via jffs2_free_inode() before JFFS2 ever > initializes it. > > This causes a double free when kfree(f->target) executes again on the > dangling pointer: > > fs/jffs2/super.c:jffs2_free_inode() { > ... > kfree(f->target); > kmem_cache_free(jffs2_inode_cachep, f); > } > > Userspace can reliably trigger the iget_locked() hash collision race by > performing concurrent lookups (e.g., stat() or open()) on the same > non-resident inode: > > fs/inode.c:iget_locked() { > ... > if (unlikely(test_bit(__I_NEW, &inode->i_state))) { > /* Uhhuh, somebody else created the same inode under us... */ > spin_unlock(&inode_hash_lock); > destroy_inode(inode); > ... > } > > Would it be safer to zero these fields in jffs2_alloc_inode() or ensure > jffs2_free_inode() nullifies them before returning the object to the slab > cache? I think this is a legit bug pointed out by Sashiko. Do you want to double check and (if needed) fix it? Thanks, //richard ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info 2026-09-09 5:57 ` Richard Weinberger @ 2026-09-10 2:53 ` Lucas Jeffrey -1 siblings, 0 replies; 12+ messages in thread From: Lucas Jeffrey @ 2026-09-10 2:53 UTC (permalink / raw) To: Richard Weinberger, linux-mtd, linux-kernel Hi richard I've sort of manually confirmed the crash pointed out by Sashiko, while not exactly the failure path mentioned in the review, I found that if immediately after returning a new inode from jffs2_alloc_inode, if allocation fails in 'security_inode_alloc', then an ENOMEM is propagated to inode_init_always_gfp and then to alloc_inode, and enters this failure path: struct inode *alloc_inode(...) { ... if (unlikely(inode_init_always(sb, inode))) { if (ops->destroy_inode) { ops->destroy_inode(inode); if (!ops->free_inode) return NULL; } inode->free_inode = ops->free_inode; i_callback(&inode->i_rcu); //Here it ends up calling jffs2_free_inode which frees f->target, double free/UAF if f->target != NULL return NULL; } ... } Here's the report [ 104.928161] ================================================================== [ 104.931812] BUG: KASAN: double-free in jffs2_free_inode+0x31/0x50 [ 104.935737] Free of addr ffff88800ad5eb80 by task repro/76 [ 104.936013] [ 104.937388] CPU: 0 UID: 0 PID: 76 Comm: repro Not tainted 7.3.0-rc2-00028-g692c6ca486c3-dirty #16 PREEMPT(lazy) [ 104.937872] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 104.938350] Call Trace: [ 104.939517] <TASK> [ 104.939999] dump_stack_lvl+0x53/0x70 [ 104.940358] print_report+0xd0/0x630 [ 104.940415] ? __pfx__raw_spin_lock_irqsave+0x10/0x10 [ 104.940459] ? jffs2_free_inode+0x31/0x50 [ 104.940486] ? jffs2_free_inode+0x31/0x50 [ 104.940509] kasan_report_invalid_free+0xa2/0xd0 [ 104.940542] ? jffs2_free_inode+0x31/0x50 [ 104.940570] ? jffs2_free_inode+0x31/0x50 [ 104.940595] check_slab_allocation+0xd9/0x100 [ 104.940625] kfree+0xfc/0x390 [ 104.940657] jffs2_free_inode+0x31/0x50 [ 104.940684] ? __pfx_jffs2_free_inode+0x10/0x10 [ 104.940715] alloc_inode+0x135/0x1f0 [ 104.940755] new_inode+0x13/0x140 [ 104.940790] jffs2_new_inode+0x77/0xa00 [ 104.940828] jffs2_create+0x8a/0x340 [ 104.940860] lookup_open+0xa90/0x18d0 [ 104.940906] path_openat+0x1257/0x2280 [ 104.940949] ? __pfx_path_openat+0x10/0x10 [ 104.940984] do_file_open+0x1cd/0x400 [ 104.941013] ? __pfx_do_file_open+0x10/0x10 [ 104.941061] ? alloc_fd+0x331/0x5b0 [ 104.941103] ? do_getname+0x66/0x2c0 [ 104.941138] do_sys_openat2+0xd9/0x170 [ 104.941168] ? __pfx_do_sys_openat2+0x10/0x10 [ 104.941203] __x64_sys_openat+0x11d/0x1d0 [ 104.941229] ? kasan_save_track+0x14/0x30 [ 104.941256] ? __pfx___x64_sys_openat+0x10/0x10 [ 104.941283] ? kmem_cache_free+0xba/0x3a0 [ 104.941310] ? fpregs_restore_userregs+0xe0/0x230 [ 104.941362] do_syscall_64+0xdd/0x4a0 [ 104.941400] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 104.941872] RIP: 0033:0x420f77 [ 104.942862] Code: 55 9c 48 89 75 a0 89 7d a8 44 89 55 ac e8 71 f0 02 00 44 8b 55 ac 8b 55 9c 41 89 c0 48 8b 75 a0 8b 7d a8 b8 01 01 00 00 0f 05 <48> 3d 00 f0 ff ff 77 31 44 89 c7 89 45 ac e8 c6 f0 02 00 8b 45 ac [ 104.943373] RSP: 002b:00007f1ef5c4e570 EFLAGS: 00000293 ORIG_RAX: 0000000000000101 [ 104.944349] RAX: ffffffffffffffda RBX: 000000000a413220 RCX: 0000000000420f77 [ 104.944401] RDX: 00000000000000c2 RSI: 00007f1ef5c4e600 RDI: 00000000ffffff9c [ 104.944447] RBP: 00007f1ef5c4e5e0 R08: 0000000000000000 R09: 0000000000000000 [ 104.944491] R10: 00000000000001a4 R11: 0000000000000293 R12: 0000000000000483 [ 104.944533] R13: 0000000000000007 R14: 00007f1ef5c4ea00 R15: 000000000a413224 [ 104.944619] </TASK> [ 104.944813] [ 104.944856] Allocated by task 78: [ 104.945202] kasan_save_stack+0x33/0x60 [ 104.945489] kasan_save_track+0x14/0x30 [ 104.945515] __kasan_kmalloc+0x8f/0xa0 [ 104.945538] __kmalloc_node_track_caller_noprof+0x1bc/0x480 [ 104.945564] kmemdup_noprof+0x20/0x50 [ 104.945600] jffs2_symlink+0x520/0x1080 [ 104.945624] vfs_symlink+0x132/0x420 [ 104.945645] filename_symlinkat+0x139/0x3d0 [ 104.945670] __x64_sys_symlink+0x74/0xa0 [ 104.945694] do_syscall_64+0xdd/0x4a0 [ 104.945720] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 104.945778] [ 104.945804] Freed by task 80: [ 104.945932] kasan_save_stack+0x33/0x60 [ 104.945984] kasan_save_track+0x14/0x30 [ 104.946074] kasan_save_free_info+0x3b/0x60 [ 104.946101] __kasan_slab_free+0x43/0x70 [ 104.946126] kfree+0x121/0x390 [ 104.946146] jffs2_free_inode+0x31/0x50 [ 104.946167] rcu_core+0x55a/0x1870 [ 104.946192] handle_softirqs+0x182/0x5a0 [ 104.946226] __irq_exit_rcu+0x63/0x140 [ 104.946248] sysvec_apic_timer_interrupt+0x6b/0x80 [ 104.946273] asm_sysvec_apic_timer_interrupt+0x1a/0x20 [ 104.946314] [ 104.946386] The buggy address belongs to the object at ffff88800ad5eb80 [ 104.946386] which belongs to the cache kmalloc-64 of size 64 [ 104.946519] The buggy address is located 0 bytes inside of [ 104.946519] 64-byte region [ffff88800ad5eb80, ffff88800ad5ebc0) [ 104.946573] [ 104.946800] The buggy address belongs to the physical page: [ 104.947880] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xad5e [ 104.948383] flags: 0x100000000000000(node=0|zone=1) [ 104.949052] page_type: f5(slab) [ 104.949572] raw: 0100000000000000 ffff8880070418c0 dead000000000100 dead000000000122 [ 104.949623] raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000 [ 104.949710] page dumped because: kasan: bad access detected [ 104.949727] [ 104.949743] Memory state around the buggy address: [ 104.950194] ffff88800ad5ea80: 00 00 00 00 00 03 fc fc fc fc fc fc fc fc fc fc [ 104.950242] ffff88800ad5eb00: 00 00 00 00 00 00 03 fc fc fc fc fc fc fc fc fc [ 104.950282] >ffff88800ad5eb80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc [ 104.950315] ^ [ 104.950381] ffff88800ad5ec00: 00 00 00 00 00 00 03 fc fc fc fc fc fc fc fc fc [ 104.950397] ffff88800ad5ec80: 00 00 00 00 00 00 03 fc fc fc fc fc fc fc fc fc [ 104.950439] ================================================================== [ 104.968624] Disabling lock debugging due to kernel taint i'll send a V2 patch that also initializes f->target = NULL when allocating the inode Thanks, Lucas J. On Wed, Sep 9, 2026 at 2:57 AM Richard Weinberger <richard@nod.at> wrote: > > Lucas, > > Am Wed, Sep 9, 2026, 04:54 schrieb sashiko-bot@kernel.org: > > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > > > > Pre-existing issues: > > - [Critical] Double free of `f->target` on early VFS failure paths due to uninitialized slab memory. > > -- > > > > commit 9fd2012cfec1b8d15df193fea97deabda99aa5e5 > > Author: Lucas Jeffrey <luquijeffrey@gmail.com> > > > > jffs: initialize inocache to NULL when initializing a jffs2_inode_info > > > > When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it > > can retain stale values from its previous use. > > > > If the new jffs2_inode_info object allocated retains an old reference to a > > freed inocache, the function jffs2_new_inode may crash if either > > jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because > > when calling iput() with the inode it will eventually attempt to free again > > the inocache. > > > > Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com > > Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 > > Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> > > > > > diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h > > > index 86ab014a349c5..40f17218a276b 100644 > > > --- a/fs/jffs2/os-linux.h > > > +++ b/fs/jffs2/os-linux.h > > > @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) > > > { > > > f->highest_version = 0; > > > f->fragtree = RB_ROOT; > > > + f->inocache = NULL; > > > f->metadata = NULL; > > > f->dents = NULL; > > > f->target = NULL; > > > > [Severity: Critical] > > This isn't a bug introduced by this patch, but doesn't f->target suffer from > > a similar issue due to uninitialized slab memory on early VFS failure paths? > > > > When the VFS allocates a new inode via jffs2_alloc_inode() in > > fs/jffs2/super.c, the object is returned from the SLAB cache without > > __GFP_ZERO. It retains stale values from its previous lifecycle, including > > a dangling pointer in f->target, because jffs2_free_inode() frees f->target > > but does not nullify it. > > > > JFFS2 defers initializing f->target = NULL to jffs2_init_inode_info(), which > > is called after VFS initialization completes. If the VFS fails early (e.g., > > inode_init_always() fails due to an LSM memory allocation, or iget_locked() > > in fs/inode.c encounters a hash collision race and drops the newly allocated > > inode), the VFS destroys the inode via jffs2_free_inode() before JFFS2 ever > > initializes it. > > > > This causes a double free when kfree(f->target) executes again on the > > dangling pointer: > > > > fs/jffs2/super.c:jffs2_free_inode() { > > ... > > kfree(f->target); > > kmem_cache_free(jffs2_inode_cachep, f); > > } > > > > Userspace can reliably trigger the iget_locked() hash collision race by > > performing concurrent lookups (e.g., stat() or open()) on the same > > non-resident inode: > > > > fs/inode.c:iget_locked() { > > ... > > if (unlikely(test_bit(__I_NEW, &inode->i_state))) { > > /* Uhhuh, somebody else created the same inode under us... */ > > spin_unlock(&inode_hash_lock); > > destroy_inode(inode); > > ... > > } > > > > Would it be safer to zero these fields in jffs2_alloc_inode() or ensure > > jffs2_free_inode() nullifies them before returning the object to the slab > > cache? > > I think this is a legit bug pointed out by Sashiko. > Do you want to double check and (if needed) fix it? > > Thanks, > //richard ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info @ 2026-09-10 2:53 ` Lucas Jeffrey 0 siblings, 0 replies; 12+ messages in thread From: Lucas Jeffrey @ 2026-09-10 2:53 UTC (permalink / raw) To: Richard Weinberger, linux-mtd, linux-kernel Hi richard I've sort of manually confirmed the crash pointed out by Sashiko, while not exactly the failure path mentioned in the review, I found that if immediately after returning a new inode from jffs2_alloc_inode, if allocation fails in 'security_inode_alloc', then an ENOMEM is propagated to inode_init_always_gfp and then to alloc_inode, and enters this failure path: struct inode *alloc_inode(...) { ... if (unlikely(inode_init_always(sb, inode))) { if (ops->destroy_inode) { ops->destroy_inode(inode); if (!ops->free_inode) return NULL; } inode->free_inode = ops->free_inode; i_callback(&inode->i_rcu); //Here it ends up calling jffs2_free_inode which frees f->target, double free/UAF if f->target != NULL return NULL; } ... } Here's the report [ 104.928161] ================================================================== [ 104.931812] BUG: KASAN: double-free in jffs2_free_inode+0x31/0x50 [ 104.935737] Free of addr ffff88800ad5eb80 by task repro/76 [ 104.936013] [ 104.937388] CPU: 0 UID: 0 PID: 76 Comm: repro Not tainted 7.3.0-rc2-00028-g692c6ca486c3-dirty #16 PREEMPT(lazy) [ 104.937872] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 104.938350] Call Trace: [ 104.939517] <TASK> [ 104.939999] dump_stack_lvl+0x53/0x70 [ 104.940358] print_report+0xd0/0x630 [ 104.940415] ? __pfx__raw_spin_lock_irqsave+0x10/0x10 [ 104.940459] ? jffs2_free_inode+0x31/0x50 [ 104.940486] ? jffs2_free_inode+0x31/0x50 [ 104.940509] kasan_report_invalid_free+0xa2/0xd0 [ 104.940542] ? jffs2_free_inode+0x31/0x50 [ 104.940570] ? jffs2_free_inode+0x31/0x50 [ 104.940595] check_slab_allocation+0xd9/0x100 [ 104.940625] kfree+0xfc/0x390 [ 104.940657] jffs2_free_inode+0x31/0x50 [ 104.940684] ? __pfx_jffs2_free_inode+0x10/0x10 [ 104.940715] alloc_inode+0x135/0x1f0 [ 104.940755] new_inode+0x13/0x140 [ 104.940790] jffs2_new_inode+0x77/0xa00 [ 104.940828] jffs2_create+0x8a/0x340 [ 104.940860] lookup_open+0xa90/0x18d0 [ 104.940906] path_openat+0x1257/0x2280 [ 104.940949] ? __pfx_path_openat+0x10/0x10 [ 104.940984] do_file_open+0x1cd/0x400 [ 104.941013] ? __pfx_do_file_open+0x10/0x10 [ 104.941061] ? alloc_fd+0x331/0x5b0 [ 104.941103] ? do_getname+0x66/0x2c0 [ 104.941138] do_sys_openat2+0xd9/0x170 [ 104.941168] ? __pfx_do_sys_openat2+0x10/0x10 [ 104.941203] __x64_sys_openat+0x11d/0x1d0 [ 104.941229] ? kasan_save_track+0x14/0x30 [ 104.941256] ? __pfx___x64_sys_openat+0x10/0x10 [ 104.941283] ? kmem_cache_free+0xba/0x3a0 [ 104.941310] ? fpregs_restore_userregs+0xe0/0x230 [ 104.941362] do_syscall_64+0xdd/0x4a0 [ 104.941400] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 104.941872] RIP: 0033:0x420f77 [ 104.942862] Code: 55 9c 48 89 75 a0 89 7d a8 44 89 55 ac e8 71 f0 02 00 44 8b 55 ac 8b 55 9c 41 89 c0 48 8b 75 a0 8b 7d a8 b8 01 01 00 00 0f 05 <48> 3d 00 f0 ff ff 77 31 44 89 c7 89 45 ac e8 c6 f0 02 00 8b 45 ac [ 104.943373] RSP: 002b:00007f1ef5c4e570 EFLAGS: 00000293 ORIG_RAX: 0000000000000101 [ 104.944349] RAX: ffffffffffffffda RBX: 000000000a413220 RCX: 0000000000420f77 [ 104.944401] RDX: 00000000000000c2 RSI: 00007f1ef5c4e600 RDI: 00000000ffffff9c [ 104.944447] RBP: 00007f1ef5c4e5e0 R08: 0000000000000000 R09: 0000000000000000 [ 104.944491] R10: 00000000000001a4 R11: 0000000000000293 R12: 0000000000000483 [ 104.944533] R13: 0000000000000007 R14: 00007f1ef5c4ea00 R15: 000000000a413224 [ 104.944619] </TASK> [ 104.944813] [ 104.944856] Allocated by task 78: [ 104.945202] kasan_save_stack+0x33/0x60 [ 104.945489] kasan_save_track+0x14/0x30 [ 104.945515] __kasan_kmalloc+0x8f/0xa0 [ 104.945538] __kmalloc_node_track_caller_noprof+0x1bc/0x480 [ 104.945564] kmemdup_noprof+0x20/0x50 [ 104.945600] jffs2_symlink+0x520/0x1080 [ 104.945624] vfs_symlink+0x132/0x420 [ 104.945645] filename_symlinkat+0x139/0x3d0 [ 104.945670] __x64_sys_symlink+0x74/0xa0 [ 104.945694] do_syscall_64+0xdd/0x4a0 [ 104.945720] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 104.945778] [ 104.945804] Freed by task 80: [ 104.945932] kasan_save_stack+0x33/0x60 [ 104.945984] kasan_save_track+0x14/0x30 [ 104.946074] kasan_save_free_info+0x3b/0x60 [ 104.946101] __kasan_slab_free+0x43/0x70 [ 104.946126] kfree+0x121/0x390 [ 104.946146] jffs2_free_inode+0x31/0x50 [ 104.946167] rcu_core+0x55a/0x1870 [ 104.946192] handle_softirqs+0x182/0x5a0 [ 104.946226] __irq_exit_rcu+0x63/0x140 [ 104.946248] sysvec_apic_timer_interrupt+0x6b/0x80 [ 104.946273] asm_sysvec_apic_timer_interrupt+0x1a/0x20 [ 104.946314] [ 104.946386] The buggy address belongs to the object at ffff88800ad5eb80 [ 104.946386] which belongs to the cache kmalloc-64 of size 64 [ 104.946519] The buggy address is located 0 bytes inside of [ 104.946519] 64-byte region [ffff88800ad5eb80, ffff88800ad5ebc0) [ 104.946573] [ 104.946800] The buggy address belongs to the physical page: [ 104.947880] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xad5e [ 104.948383] flags: 0x100000000000000(node=0|zone=1) [ 104.949052] page_type: f5(slab) [ 104.949572] raw: 0100000000000000 ffff8880070418c0 dead000000000100 dead000000000122 [ 104.949623] raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000 [ 104.949710] page dumped because: kasan: bad access detected [ 104.949727] [ 104.949743] Memory state around the buggy address: [ 104.950194] ffff88800ad5ea80: 00 00 00 00 00 03 fc fc fc fc fc fc fc fc fc fc [ 104.950242] ffff88800ad5eb00: 00 00 00 00 00 00 03 fc fc fc fc fc fc fc fc fc [ 104.950282] >ffff88800ad5eb80: fa fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc [ 104.950315] ^ [ 104.950381] ffff88800ad5ec00: 00 00 00 00 00 00 03 fc fc fc fc fc fc fc fc fc [ 104.950397] ffff88800ad5ec80: 00 00 00 00 00 00 03 fc fc fc fc fc fc fc fc fc [ 104.950439] ================================================================== [ 104.968624] Disabling lock debugging due to kernel taint i'll send a V2 patch that also initializes f->target = NULL when allocating the inode Thanks, Lucas J. On Wed, Sep 9, 2026 at 2:57 AM Richard Weinberger <richard@nod.at> wrote: > > Lucas, > > Am Wed, Sep 9, 2026, 04:54 schrieb sashiko-bot@kernel.org: > > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > > > > Pre-existing issues: > > - [Critical] Double free of `f->target` on early VFS failure paths due to uninitialized slab memory. > > -- > > > > commit 9fd2012cfec1b8d15df193fea97deabda99aa5e5 > > Author: Lucas Jeffrey <luquijeffrey@gmail.com> > > > > jffs: initialize inocache to NULL when initializing a jffs2_inode_info > > > > When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it > > can retain stale values from its previous use. > > > > If the new jffs2_inode_info object allocated retains an old reference to a > > freed inocache, the function jffs2_new_inode may crash if either > > jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because > > when calling iput() with the inode it will eventually attempt to free again > > the inocache. > > > > Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com > > Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 > > Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> > > > > > diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h > > > index 86ab014a349c5..40f17218a276b 100644 > > > --- a/fs/jffs2/os-linux.h > > > +++ b/fs/jffs2/os-linux.h > > > @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) > > > { > > > f->highest_version = 0; > > > f->fragtree = RB_ROOT; > > > + f->inocache = NULL; > > > f->metadata = NULL; > > > f->dents = NULL; > > > f->target = NULL; > > > > [Severity: Critical] > > This isn't a bug introduced by this patch, but doesn't f->target suffer from > > a similar issue due to uninitialized slab memory on early VFS failure paths? > > > > When the VFS allocates a new inode via jffs2_alloc_inode() in > > fs/jffs2/super.c, the object is returned from the SLAB cache without > > __GFP_ZERO. It retains stale values from its previous lifecycle, including > > a dangling pointer in f->target, because jffs2_free_inode() frees f->target > > but does not nullify it. > > > > JFFS2 defers initializing f->target = NULL to jffs2_init_inode_info(), which > > is called after VFS initialization completes. If the VFS fails early (e.g., > > inode_init_always() fails due to an LSM memory allocation, or iget_locked() > > in fs/inode.c encounters a hash collision race and drops the newly allocated > > inode), the VFS destroys the inode via jffs2_free_inode() before JFFS2 ever > > initializes it. > > > > This causes a double free when kfree(f->target) executes again on the > > dangling pointer: > > > > fs/jffs2/super.c:jffs2_free_inode() { > > ... > > kfree(f->target); > > kmem_cache_free(jffs2_inode_cachep, f); > > } > > > > Userspace can reliably trigger the iget_locked() hash collision race by > > performing concurrent lookups (e.g., stat() or open()) on the same > > non-resident inode: > > > > fs/inode.c:iget_locked() { > > ... > > if (unlikely(test_bit(__I_NEW, &inode->i_state))) { > > /* Uhhuh, somebody else created the same inode under us... */ > > spin_unlock(&inode_hash_lock); > > destroy_inode(inode); > > ... > > } > > > > Would it be safer to zero these fields in jffs2_alloc_inode() or ensure > > jffs2_free_inode() nullifies them before returning the object to the slab > > cache? > > I think this is a legit bug pointed out by Sashiko. > Do you want to double check and (if needed) fix it? > > Thanks, > //richard ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 12+ messages in thread
* AW: [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info 2026-09-09 2:39 ` Lucas Jeffrey @ 2026-09-09 5:33 ` Richard Weinberger -1 siblings, 0 replies; 12+ messages in thread From: Richard Weinberger @ 2026-09-09 5:33 UTC (permalink / raw) To: Lucas Jeffrey, dwmw2 Cc: linux-mtd, linux-kernel, Lucas Jeffrey, syzbot+3a8099322b09d8d073d1 Am Wed, Sep 9, 2026, 04:40 schrieb Lucas Jeffrey <luquijeffrey@gmail.com>: > When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it > can retain stale values from its previous use. > > If the new jffs2_inode_info object allocated retains an old reference to a > freed inocache, the function jffs2_new_inode may crash if either > jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because > when calling iput() with the inode it will eventually attempt to free again > the inocache. > > Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com > Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 > Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> This was reported earlier but the reporter went silent. https://lore.kernel.org/linux-mtd/849183271.921.1787173413104.JavaMail.zimbra@nod.at/ Thanks, //richard ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply [flat|nested] 12+ messages in thread
* AW: [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info @ 2026-09-09 5:33 ` Richard Weinberger 0 siblings, 0 replies; 12+ messages in thread From: Richard Weinberger @ 2026-09-09 5:33 UTC (permalink / raw) To: Lucas Jeffrey, dwmw2 Cc: linux-mtd, linux-kernel, Lucas Jeffrey, syzbot+3a8099322b09d8d073d1 Am Wed, Sep 9, 2026, 04:40 schrieb Lucas Jeffrey <luquijeffrey@gmail.com>: > When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it > can retain stale values from its previous use. > > If the new jffs2_inode_info object allocated retains an old reference to a > freed inocache, the function jffs2_new_inode may crash if either > jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because > when calling iput() with the inode it will eventually attempt to free again > the inocache. > > Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com > Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 > Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> This was reported earlier but the reporter went silent. https://lore.kernel.org/linux-mtd/849183271.921.1787173413104.JavaMail.zimbra@nod.at/ Thanks, //richard ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2] jffs2: initialize inocache and target to NULL when allocating and initializing an jffs2_inode_info 2026-09-09 2:39 ` Lucas Jeffrey @ 2026-09-10 3:19 ` Lucas Jeffrey -1 siblings, 0 replies; 12+ messages in thread From: Lucas Jeffrey @ 2026-09-10 3:19 UTC (permalink / raw) To: dwmw2 Cc: richard, linux-mtd, linux-kernel, syzbot+3a8099322b09d8d073d1, Lucas Jeffrey When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it can retain stale values from its previous use. If the new jffs2_inode_info object allocated retains an old reference to a freed inocache, the function jffs2_new_inode may crash if either jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because when calling iput() with the inode it will eventually attempt to free again the inocache. There is another failure path which is, if target is not null when allocating the object in jffs2_alloc_inode, and immediately after returning the newly allocated object, and if the 'inode_init_always' returns an error value (allocation failure for example) then the vfs will attempt to free the inode and jffs2_free_inode will attempt to free f->target, which can be a stale value from a previous allocation, generating a double free/use after free. Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> --- Changes in V2: initializing target field to NULL in jffs2_alloc_inode --- fs/jffs2/os-linux.h | 1 + fs/jffs2/super.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 86ab014a349c..40f17218a276 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { f->highest_version = 0; f->fragtree = RB_ROOT; + f->inocache = NULL; f->metadata = NULL; f->dents = NULL; f->target = NULL; diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 81396a092ba8..2343c21b49e6 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -42,6 +42,8 @@ static struct inode *jffs2_alloc_inode(struct super_block *sb) f = alloc_inode_sb(sb, jffs2_inode_cachep, GFP_KERNEL); if (!f) return NULL; + + f->target = NULL; return &f->vfs_inode; } -- 2.43.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2] jffs2: initialize inocache and target to NULL when allocating and initializing an jffs2_inode_info @ 2026-09-10 3:19 ` Lucas Jeffrey 0 siblings, 0 replies; 12+ messages in thread From: Lucas Jeffrey @ 2026-09-10 3:19 UTC (permalink / raw) To: dwmw2 Cc: richard, linux-mtd, linux-kernel, syzbot+3a8099322b09d8d073d1, Lucas Jeffrey When a jffs2_inode_info is allocated via new_inode(), due to memory reuse it can retain stale values from its previous use. If the new jffs2_inode_info object allocated retains an old reference to a freed inocache, the function jffs2_new_inode may crash if either jffs2_init_acl_pre or jffs2_do_new_inode returns an error value because when calling iput() with the inode it will eventually attempt to free again the inocache. There is another failure path which is, if target is not null when allocating the object in jffs2_alloc_inode, and immediately after returning the newly allocated object, and if the 'inode_init_always' returns an error value (allocation failure for example) then the vfs will attempt to free the inode and jffs2_free_inode will attempt to free f->target, which can be a stale value from a previous allocation, generating a double free/use after free. Reported-by: syzbot+3a8099322b09d8d073d1@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3a8099322b09d8d073d1 Signed-off-by: Lucas Jeffrey <luquijeffrey@gmail.com> --- Changes in V2: initializing target field to NULL in jffs2_alloc_inode --- fs/jffs2/os-linux.h | 1 + fs/jffs2/super.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 86ab014a349c..40f17218a276 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -52,6 +52,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { f->highest_version = 0; f->fragtree = RB_ROOT; + f->inocache = NULL; f->metadata = NULL; f->dents = NULL; f->target = NULL; diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 81396a092ba8..2343c21b49e6 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -42,6 +42,8 @@ static struct inode *jffs2_alloc_inode(struct super_block *sb) f = alloc_inode_sb(sb, jffs2_inode_cachep, GFP_KERNEL); if (!f) return NULL; + + f->target = NULL; return &f->vfs_inode; } -- 2.43.0 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ ^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-09-10 3:19 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-09 2:39 [PATCH] jffs: initialize inocache to NULL when initializing a jffs2_inode_info Lucas Jeffrey 2026-09-09 2:39 ` Lucas Jeffrey 2026-09-09 2:54 ` sashiko-bot 2026-09-09 2:54 ` sashiko-bot 2026-09-09 5:57 ` AW: " Richard Weinberger 2026-09-09 5:57 ` Richard Weinberger 2026-09-10 2:53 ` Lucas Jeffrey 2026-09-10 2:53 ` Lucas Jeffrey 2026-09-09 5:33 ` AW: " Richard Weinberger 2026-09-09 5:33 ` Richard Weinberger 2026-09-10 3:19 ` [PATCH v2] jffs2: initialize inocache and target to NULL when allocating and initializing an jffs2_inode_info Lucas Jeffrey 2026-09-10 3:19 ` Lucas Jeffrey
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.