* Forwarded: [PATCH] fs: fix stale inode access in chown_common() retry path
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
@ 2025-10-17 8:57 ` syzbot
2025-10-17 8:57 ` syzbot
` (9 subsequent siblings)
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-10-17 8:57 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix stale inode access in chown_common() retry path
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
When chown_common() retries due to delegation, it reuses the inode
pointer fetched before the retry_deleg label. However, break_deleg_wait()
can cause the dentry to be updated, making path->dentry->d_inode point
to a different inode. The stale inode pointer leads to locking/unlocking
an invalid or freed inode, triggering a rwsem warning.
The issue manifests as:
WARNING: CPU: 0 PID: 5699 at kernel/locking/rwsem.c:1381 up_write+0x3a2/0x420
DEBUG_RWSEMS_WARN_ON((rwsem_owner(sem) != current) &&
!rwsem_test_oflags(sem, RWSEM_NONSPINNABLE)):
count = 0x0, owner = 0x0
Fix by refreshing both the inode pointer and its associated filesystem
user namespace on each retry iteration, ensuring operations are always
performed on the current, valid inode.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/open.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..8672072fb4c1 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -755,7 +755,7 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
{
struct mnt_idmap *idmap;
struct user_namespace *fs_userns;
- struct inode *inode = path->dentry->d_inode;
+ struct inode *inode;
struct inode *delegated_inode = NULL;
int error;
struct iattr newattrs;
@@ -766,9 +766,10 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
gid = make_kgid(current_user_ns(), group);
idmap = mnt_idmap(path->mnt);
- fs_userns = i_user_ns(inode);
retry_deleg:
+ inode = path->dentry->d_inode;
+ fs_userns = i_user_ns(inode);
newattrs.ia_vfsuid = INVALID_VFSUID;
newattrs.ia_vfsgid = INVALID_VFSGID;
newattrs.ia_valid = ATTR_CTIME;
--
2.34.1
^ permalink raw reply related [flat|nested] 26+ messages in thread* Forwarded: [PATCH] fs: fix stale inode access in chown_common() retry path
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
2025-10-17 8:57 ` Forwarded: [PATCH] fs: fix stale inode access in chown_common() retry path syzbot
@ 2025-10-17 8:57 ` syzbot
2025-10-29 8:23 ` Forwarded: Test patch for [syzbot] [gfs2?] WARNING in chown_common syzbot
` (8 subsequent siblings)
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-10-17 8:57 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix stale inode access in chown_common() retry path
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
When chown_common() retries due to delegation, it reuses the inode
pointer fetched before the retry_deleg label. However, break_deleg_wait()
can cause the dentry to be updated, making path->dentry->d_inode point
to a different inode. The stale inode pointer leads to locking/unlocking
an invalid or freed inode, triggering a rwsem warning.
The issue manifests as:
WARNING: CPU: 0 PID: 5699 at kernel/locking/rwsem.c:1381 up_write+0x3a2/0x420
DEBUG_RWSEMS_WARN_ON((rwsem_owner(sem) != current) &&
!rwsem_test_oflags(sem, RWSEM_NONSPINNABLE)):
count = 0x0, owner = 0x0
Fix by refreshing both the inode pointer and its associated filesystem
user namespace on each retry iteration, ensuring operations are always
performed on the current, valid inode.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/open.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..8672072fb4c1 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -755,7 +755,7 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
{
struct mnt_idmap *idmap;
struct user_namespace *fs_userns;
- struct inode *inode = path->dentry->d_inode;
+ struct inode *inode;
struct inode *delegated_inode = NULL;
int error;
struct iattr newattrs;
@@ -766,9 +766,10 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
gid = make_kgid(current_user_ns(), group);
idmap = mnt_idmap(path->mnt);
- fs_userns = i_user_ns(inode);
retry_deleg:
+ inode = path->dentry->d_inode;
+ fs_userns = i_user_ns(inode);
newattrs.ia_vfsuid = INVALID_VFSUID;
newattrs.ia_vfsgid = INVALID_VFSGID;
newattrs.ia_valid = ATTR_CTIME;
--
2.34.1
^ permalink raw reply related [flat|nested] 26+ messages in thread* Forwarded: Test patch for [syzbot] [gfs2?] WARNING in chown_common
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
2025-10-17 8:57 ` Forwarded: [PATCH] fs: fix stale inode access in chown_common() retry path syzbot
2025-10-17 8:57 ` syzbot
@ 2025-10-29 8:23 ` syzbot
2025-11-09 5:02 ` Forwarded: [PATCH] fs: fix inode reference leak in chown_common delegation retry path syzbot
` (7 subsequent siblings)
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-10-29 8:23 UTC (permalink / raw)
To: linux-kernel
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org.
***
Subject: Test patch for [syzbot] [gfs2?] WARNING in chown_common
Author: vnranganath.20@gmail.com
#syz test
^ permalink raw reply [flat|nested] 26+ messages in thread* Forwarded: [PATCH] fs: fix inode reference leak in chown_common delegation retry path
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
` (2 preceding siblings ...)
2025-10-29 8:23 ` Forwarded: Test patch for [syzbot] [gfs2?] WARNING in chown_common syzbot
@ 2025-11-09 5:02 ` syzbot
2025-11-09 9:08 ` Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry syzbot
` (6 subsequent siblings)
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-11-09 5:02 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix inode reference leak in chown_common delegation retry path
Author: kartikey406@gmail.com
#syz test git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
The chown_common() function can trigger a use-after-free when retrying
after breaking a file delegation. The issue occurs because break_deleg_wait()
calls iput() on the delegated inode, potentially freeing it if this was the
last reference. However, chown_common() continues to use the stale inode
pointer on retry, leading to operations on a freed or reused inode.
This manifests as a rwsem warning:
DEBUG_RWSEMS_WARN_ON((rwsem_owner(sem) != current) &&
!rwsem_test_oflags(sem, RWSEM_NONSPINNABLE))
owner = 0x0
The warning occurs because the inode's rwsem is in an invalid state after
the inode has been freed or reused by another thread.
The bug is particularly reproducible on GFS2 filesystem where delegations
are more common due to its clustered nature, and can be triggered by
concurrent fchownat() calls on the same file.
Fix this by:
1. Re-fetching the inode pointer from path->dentry->d_inode on each
iteration at the retry_deleg label
2. Holding an explicit reference with ihold() at the start of each iteration
3. Releasing the reference with iput() on all exit paths, including before
the retry
This ensures the inode remains valid throughout the delegation break and
retry sequence, preventing use-after-free.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/open.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..a564f05c0c91 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -755,7 +755,7 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
{
struct mnt_idmap *idmap;
struct user_namespace *fs_userns;
- struct inode *inode = path->dentry->d_inode;
+ struct inode *inode;
struct inode *delegated_inode = NULL;
int error;
struct iattr newattrs;
@@ -766,19 +766,27 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
gid = make_kgid(current_user_ns(), group);
idmap = mnt_idmap(path->mnt);
- fs_userns = i_user_ns(inode);
retry_deleg:
+ inode = path->dentry->d_inode;
+ ihold(inode);
+ fs_userns = i_user_ns(inode);
newattrs.ia_vfsuid = INVALID_VFSUID;
newattrs.ia_vfsgid = INVALID_VFSGID;
newattrs.ia_valid = ATTR_CTIME;
- if ((user != (uid_t)-1) && !setattr_vfsuid(&newattrs, uid))
+ if ((user != (uid_t)-1) && !setattr_vfsuid(&newattrs, uid)) {
+ iput(inode);
return -EINVAL;
- if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid))
+ }
+ if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid)) {
+ iput(inode);
return -EINVAL;
+ }
error = inode_lock_killable(inode);
- if (error)
+ if (error) {
+ iput(inode);
return error;
+ }
if (!S_ISDIR(inode->i_mode))
newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV |
setattr_should_drop_sgid(idmap, inode);
@@ -793,9 +801,12 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
inode_unlock(inode);
if (delegated_inode) {
error = break_deleg_wait(&delegated_inode);
- if (!error)
+ if (!error) {
+ iput(inode);
goto retry_deleg;
+ }
}
+ iput(inode);
return error;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
` (3 preceding siblings ...)
2025-11-09 5:02 ` Forwarded: [PATCH] fs: fix inode reference leak in chown_common delegation retry path syzbot
@ 2025-11-09 9:08 ` syzbot
2025-11-09 11:05 ` kernel test robot
2025-11-09 12:17 ` kernel test robot
2025-11-09 11:40 ` syzbot
` (5 subsequent siblings)
10 siblings, 2 replies; 26+ messages in thread
From: syzbot @ 2025-11-09 9:08 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
Author: kartikey406@gmail.com
#syz test git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
The chown_common() function has a use-after-free bug in its delegation
retry path. When break_deleg_wait() is called, it internally calls
iput() on the delegated inode, potentially freeing it if this was the
last reference. However, chown_common() continues using the stale inode
pointer on retry, leading to operations on freed memory.
This manifests as a rwsem warning where the inode's rwsem owner field
is corrupted:
DEBUG_RWSEMS_WARN_ON: owner = 0x0
The bug is triggered by concurrent fchownat() calls and is reproducible
on GFS2 filesystems where delegations are common.
Fix by:
1. Re-fetching inode from path->dentry->d_inode on each retry iteration
2. Holding an explicit inode reference with ihold() at iteration start
3. Releasing the reference with iput() on all exit paths
This ensures the inode remains valid throughout delegation break and retry.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/open.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..bbd73984292d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -769,6 +769,9 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
fs_userns = i_user_ns(inode);
retry_deleg:
+ printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
+ current->comm, inode, atomic_read(&inode->i_count),
+ atomic_long_read(&inode->i_rwsem.owner));
newattrs.ia_vfsuid = INVALID_VFSUID;
newattrs.ia_vfsgid = INVALID_VFSGID;
newattrs.ia_valid = ATTR_CTIME;
@@ -776,9 +779,13 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
return -EINVAL;
if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid))
return -EINVAL;
+ printk("DEBUG: [%s] before inode_lock: inode=%p, i_count=%d\n",
+ current->comm, inode, atomic_read(&inode->i_count));
error = inode_lock_killable(inode);
if (error)
return error;
+ printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
+ current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), current);
if (!S_ISDIR(inode->i_mode))
newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV |
setattr_should_drop_sgid(idmap, inode);
@@ -790,9 +797,17 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
if (!error)
error = notify_change(idmap, path->dentry, &newattrs,
&delegated_inode);
+ printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
+ current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), delegated_inode);
inode_unlock(inode);
+ printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
+ current->comm, inode, atomic_long_read(&inode->i_rwsem.owner));
if (delegated_inode) {
+ printk("DEBUG: [%s] calling break_deleg_wait: inode=%p, i_count=%d, delegated_inode=%p\n",
+ current->comm, inode, atomic_read(&inode->i_count), delegated_inode);
error = break_deleg_wait(&delegated_inode);
+ printk("DEBUG: [%s] after break_deleg_wait: inode=%p, i_count=%d, error=%d\n",
+ current->comm, inode, atomic_read(&inode->i_count), error);
if (!error)
goto retry_deleg;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-11-09 9:08 ` Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry syzbot
@ 2025-11-09 11:05 ` kernel test robot
2025-11-09 12:26 ` Philip Li
2025-11-09 12:17 ` kernel test robot
1 sibling, 1 reply; 26+ messages in thread
From: kernel test robot @ 2025-11-09 11:05 UTC (permalink / raw)
To: syzbot, linux-kernel, syzkaller-bugs; +Cc: llvm, oe-kbuild-all
Hi syzbot,
kernel test robot noticed the following build warnings:
[auto build test WARNING on brauner-vfs/vfs.all]
[also build test WARNING on linus/master v6.18-rc4 next-20251107]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/syzbot/Forwarded-PATCH-fs-fix-inode-use-after-free-in-chown_common-delegation-retry/20251109-171000
base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link: https://lore.kernel.org/r/691059ff.a70a0220.22f260.00a6.GAE%40google.com
patch subject: Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
config: arm-allnoconfig (https://download.01.org/0day-ci/archive/20251109/202511091815.6q5WUuzH-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project b9ea93cd5c37fb6d606502fd01208dd48330549d)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251109/202511091815.6q5WUuzH-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511091815.6q5WUuzH-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> fs/open.c:771:9: warning: format specifies type 'void *' but the argument has type 'long' [-Wformat]
769 | printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
| ~~
| %ld
770 | current->comm, inode, atomic_read(&inode->i_count),
771 | atomic_long_read(&inode->i_rwsem.owner));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/printk.h:512:60: note: expanded from macro 'printk'
512 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/printk.h:484:19: note: expanded from macro 'printk_index_wrap'
484 | _p_func(_fmt, ##__VA_ARGS__); \
| ~~~~ ^~~~~~~~~~~
fs/open.c:785:31: warning: format specifies type 'void *' but the argument has type 'long' [-Wformat]
784 | printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
| ~~
| %ld
785 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), current);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/printk.h:512:60: note: expanded from macro 'printk'
512 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/printk.h:484:19: note: expanded from macro 'printk_index_wrap'
484 | _p_func(_fmt, ##__VA_ARGS__); \
| ~~~~ ^~~~~~~~~~~
fs/open.c:798:31: warning: format specifies type 'void *' but the argument has type 'long' [-Wformat]
797 | printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
| ~~
| %ld
798 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), delegated_inode);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/printk.h:512:60: note: expanded from macro 'printk'
512 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/printk.h:484:19: note: expanded from macro 'printk_index_wrap'
484 | _p_func(_fmt, ##__VA_ARGS__); \
| ~~~~ ^~~~~~~~~~~
fs/open.c:801:31: warning: format specifies type 'void *' but the argument has type 'long' [-Wformat]
800 | printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
| ~~
| %ld
801 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/printk.h:512:60: note: expanded from macro 'printk'
512 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/printk.h:484:19: note: expanded from macro 'printk_index_wrap'
484 | _p_func(_fmt, ##__VA_ARGS__); \
| ~~~~ ^~~~~~~~~~~
4 warnings generated.
vim +771 fs/open.c
750
751 int chown_common(const struct path *path, uid_t user, gid_t group)
752 {
753 struct mnt_idmap *idmap;
754 struct user_namespace *fs_userns;
755 struct inode *inode = path->dentry->d_inode;
756 struct inode *delegated_inode = NULL;
757 int error;
758 struct iattr newattrs;
759 kuid_t uid;
760 kgid_t gid;
761
762 uid = make_kuid(current_user_ns(), user);
763 gid = make_kgid(current_user_ns(), group);
764
765 idmap = mnt_idmap(path->mnt);
766 fs_userns = i_user_ns(inode);
767
768 retry_deleg:
769 printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
770 current->comm, inode, atomic_read(&inode->i_count),
> 771 atomic_long_read(&inode->i_rwsem.owner));
772 newattrs.ia_vfsuid = INVALID_VFSUID;
773 newattrs.ia_vfsgid = INVALID_VFSGID;
774 newattrs.ia_valid = ATTR_CTIME;
775 if ((user != (uid_t)-1) && !setattr_vfsuid(&newattrs, uid))
776 return -EINVAL;
777 if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid))
778 return -EINVAL;
779 printk("DEBUG: [%s] before inode_lock: inode=%p, i_count=%d\n",
780 current->comm, inode, atomic_read(&inode->i_count));
781 error = inode_lock_killable(inode);
782 if (error)
783 return error;
784 printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
785 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), current);
786 if (!S_ISDIR(inode->i_mode))
787 newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV |
788 setattr_should_drop_sgid(idmap, inode);
789 /* Continue to send actual fs values, not the mount values. */
790 error = security_path_chown(
791 path,
792 from_vfsuid(idmap, fs_userns, newattrs.ia_vfsuid),
793 from_vfsgid(idmap, fs_userns, newattrs.ia_vfsgid));
794 if (!error)
795 error = notify_change(idmap, path->dentry, &newattrs,
796 &delegated_inode);
797 printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
798 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), delegated_inode);
799 inode_unlock(inode);
800 printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
801 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner));
802 if (delegated_inode) {
803 printk("DEBUG: [%s] calling break_deleg_wait: inode=%p, i_count=%d, delegated_inode=%p\n",
804 current->comm, inode, atomic_read(&inode->i_count), delegated_inode);
805 error = break_deleg_wait(&delegated_inode);
806 printk("DEBUG: [%s] after break_deleg_wait: inode=%p, i_count=%d, error=%d\n",
807 current->comm, inode, atomic_read(&inode->i_count), error);
808 if (!error)
809 goto retry_deleg;
810 }
811 return error;
812 }
813
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-11-09 11:05 ` kernel test robot
@ 2025-11-09 12:26 ` Philip Li
0 siblings, 0 replies; 26+ messages in thread
From: Philip Li @ 2025-11-09 12:26 UTC (permalink / raw)
To: kernel test robot
Cc: syzbot, linux-kernel, syzkaller-bugs, llvm, oe-kbuild-all
On Sun, Nov 09, 2025 at 07:05:11PM +0800, kernel test robot wrote:
> Hi syzbot,
>
> kernel test robot noticed the following build warnings:
Sorry, kindly ignore this report.
>
> [auto build test WARNING on brauner-vfs/vfs.all]
> [also build test WARNING on linus/master v6.18-rc4 next-20251107]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url: https://github.com/intel-lab-lkp/linux/commits/syzbot/Forwarded-PATCH-fs-fix-inode-use-after-free-in-chown_common-delegation-retry/20251109-171000
> base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
> patch link: https://lore.kernel.org/r/691059ff.a70a0220.22f260.00a6.GAE%40google.com
> patch subject: Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
> config: arm-allnoconfig (https://download.01.org/0day-ci/archive/20251109/202511091815.6q5WUuzH-lkp@intel.com/config)
> compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project b9ea93cd5c37fb6d606502fd01208dd48330549d)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251109/202511091815.6q5WUuzH-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202511091815.6q5WUuzH-lkp@intel.com/
>
> All warnings (new ones prefixed by >>):
>
> >> fs/open.c:771:9: warning: format specifies type 'void *' but the argument has type 'long' [-Wformat]
> 769 | printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
> | ~~
> | %ld
> 770 | current->comm, inode, atomic_read(&inode->i_count),
> 771 | atomic_long_read(&inode->i_rwsem.owner));
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> include/linux/printk.h:512:60: note: expanded from macro 'printk'
> 512 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
> | ~~~ ^~~~~~~~~~~
> include/linux/printk.h:484:19: note: expanded from macro 'printk_index_wrap'
> 484 | _p_func(_fmt, ##__VA_ARGS__); \
> | ~~~~ ^~~~~~~~~~~
> fs/open.c:785:31: warning: format specifies type 'void *' but the argument has type 'long' [-Wformat]
> 784 | printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
> | ~~
> | %ld
> 785 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), current);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> include/linux/printk.h:512:60: note: expanded from macro 'printk'
> 512 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
> | ~~~ ^~~~~~~~~~~
> include/linux/printk.h:484:19: note: expanded from macro 'printk_index_wrap'
> 484 | _p_func(_fmt, ##__VA_ARGS__); \
> | ~~~~ ^~~~~~~~~~~
> fs/open.c:798:31: warning: format specifies type 'void *' but the argument has type 'long' [-Wformat]
> 797 | printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
> | ~~
> | %ld
> 798 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), delegated_inode);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> include/linux/printk.h:512:60: note: expanded from macro 'printk'
> 512 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
> | ~~~ ^~~~~~~~~~~
> include/linux/printk.h:484:19: note: expanded from macro 'printk_index_wrap'
> 484 | _p_func(_fmt, ##__VA_ARGS__); \
> | ~~~~ ^~~~~~~~~~~
> fs/open.c:801:31: warning: format specifies type 'void *' but the argument has type 'long' [-Wformat]
> 800 | printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
> | ~~
> | %ld
> 801 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner));
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> include/linux/printk.h:512:60: note: expanded from macro 'printk'
> 512 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
> | ~~~ ^~~~~~~~~~~
> include/linux/printk.h:484:19: note: expanded from macro 'printk_index_wrap'
> 484 | _p_func(_fmt, ##__VA_ARGS__); \
> | ~~~~ ^~~~~~~~~~~
> 4 warnings generated.
>
>
> vim +771 fs/open.c
>
> 750
> 751 int chown_common(const struct path *path, uid_t user, gid_t group)
> 752 {
> 753 struct mnt_idmap *idmap;
> 754 struct user_namespace *fs_userns;
> 755 struct inode *inode = path->dentry->d_inode;
> 756 struct inode *delegated_inode = NULL;
> 757 int error;
> 758 struct iattr newattrs;
> 759 kuid_t uid;
> 760 kgid_t gid;
> 761
> 762 uid = make_kuid(current_user_ns(), user);
> 763 gid = make_kgid(current_user_ns(), group);
> 764
> 765 idmap = mnt_idmap(path->mnt);
> 766 fs_userns = i_user_ns(inode);
> 767
> 768 retry_deleg:
> 769 printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
> 770 current->comm, inode, atomic_read(&inode->i_count),
> > 771 atomic_long_read(&inode->i_rwsem.owner));
> 772 newattrs.ia_vfsuid = INVALID_VFSUID;
> 773 newattrs.ia_vfsgid = INVALID_VFSGID;
> 774 newattrs.ia_valid = ATTR_CTIME;
> 775 if ((user != (uid_t)-1) && !setattr_vfsuid(&newattrs, uid))
> 776 return -EINVAL;
> 777 if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid))
> 778 return -EINVAL;
> 779 printk("DEBUG: [%s] before inode_lock: inode=%p, i_count=%d\n",
> 780 current->comm, inode, atomic_read(&inode->i_count));
> 781 error = inode_lock_killable(inode);
> 782 if (error)
> 783 return error;
> 784 printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
> 785 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), current);
> 786 if (!S_ISDIR(inode->i_mode))
> 787 newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV |
> 788 setattr_should_drop_sgid(idmap, inode);
> 789 /* Continue to send actual fs values, not the mount values. */
> 790 error = security_path_chown(
> 791 path,
> 792 from_vfsuid(idmap, fs_userns, newattrs.ia_vfsuid),
> 793 from_vfsgid(idmap, fs_userns, newattrs.ia_vfsgid));
> 794 if (!error)
> 795 error = notify_change(idmap, path->dentry, &newattrs,
> 796 &delegated_inode);
> 797 printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
> 798 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), delegated_inode);
> 799 inode_unlock(inode);
> 800 printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
> 801 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner));
> 802 if (delegated_inode) {
> 803 printk("DEBUG: [%s] calling break_deleg_wait: inode=%p, i_count=%d, delegated_inode=%p\n",
> 804 current->comm, inode, atomic_read(&inode->i_count), delegated_inode);
> 805 error = break_deleg_wait(&delegated_inode);
> 806 printk("DEBUG: [%s] after break_deleg_wait: inode=%p, i_count=%d, error=%d\n",
> 807 current->comm, inode, atomic_read(&inode->i_count), error);
> 808 if (!error)
> 809 goto retry_deleg;
> 810 }
> 811 return error;
> 812 }
> 813
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-11-09 9:08 ` Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry syzbot
2025-11-09 11:05 ` kernel test robot
@ 2025-11-09 12:17 ` kernel test robot
2025-11-09 12:26 ` Philip Li
1 sibling, 1 reply; 26+ messages in thread
From: kernel test robot @ 2025-11-09 12:17 UTC (permalink / raw)
To: syzbot, linux-kernel, syzkaller-bugs; +Cc: oe-kbuild-all
Hi syzbot,
kernel test robot noticed the following build warnings:
[auto build test WARNING on brauner-vfs/vfs.all]
[also build test WARNING on linus/master v6.18-rc4 next-20251107]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/syzbot/Forwarded-PATCH-fs-fix-inode-use-after-free-in-chown_common-delegation-retry/20251109-171000
base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link: https://lore.kernel.org/r/691059ff.a70a0220.22f260.00a6.GAE%40google.com
patch subject: Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
config: i386-allnoconfig (https://download.01.org/0day-ci/archive/20251109/202511091831.tPcsumuB-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251109/202511091831.tPcsumuB-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511091831.tPcsumuB-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from include/asm-generic/bug.h:22,
from arch/x86/include/asm/bug.h:108,
from include/linux/bug.h:5,
from include/linux/mmdebug.h:5,
from include/linux/mm.h:6,
from fs/open.c:9:
fs/open.c: In function 'chown_common':
>> fs/open.c:769:16: warning: format '%p' expects argument of type 'void *', but argument 5 has type 'long int' [-Wformat=]
769 | printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
770 | current->comm, inode, atomic_read(&inode->i_count),
771 | atomic_long_read(&inode->i_rwsem.owner));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| long int
include/linux/printk.h:484:25: note: in definition of macro 'printk_index_wrap'
484 | _p_func(_fmt, ##__VA_ARGS__); \
| ^~~~
fs/open.c:769:9: note: in expansion of macro 'printk'
769 | printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
| ^~~~~~
fs/open.c:769:79: note: format string is defined here
769 | printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
| ~^
| |
| void *
| %ld
fs/open.c:784:16: warning: format '%p' expects argument of type 'void *', but argument 4 has type 'long int' [-Wformat=]
784 | printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
785 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), current);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| long int
include/linux/printk.h:484:25: note: in definition of macro 'printk_index_wrap'
484 | _p_func(_fmt, ##__VA_ARGS__); \
| ^~~~
fs/open.c:784:9: note: in expansion of macro 'printk'
784 | printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
| ^~~~~~
fs/open.c:784:72: note: format string is defined here
784 | printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
| ~^
| |
| void *
| %ld
fs/open.c:797:16: warning: format '%p' expects argument of type 'void *', but argument 4 has type 'long int' [-Wformat=]
797 | printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
798 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), delegated_inode);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| long int
include/linux/printk.h:484:25: note: in definition of macro 'printk_index_wrap'
484 | _p_func(_fmt, ##__VA_ARGS__); \
| ^~~~
fs/open.c:797:9: note: in expansion of macro 'printk'
797 | printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
| ^~~~~~
fs/open.c:797:75: note: format string is defined here
797 | printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
| ~^
| |
| void *
| %ld
fs/open.c:800:16: warning: format '%p' expects argument of type 'void *', but argument 4 has type 'long int' [-Wformat=]
800 | printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
801 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| long int
include/linux/printk.h:484:25: note: in definition of macro 'printk_index_wrap'
484 | _p_func(_fmt, ##__VA_ARGS__); \
| ^~~~
fs/open.c:800:9: note: in expansion of macro 'printk'
800 | printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
| ^~~~~~
fs/open.c:800:74: note: format string is defined here
800 | printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
| ~^
| |
| void *
| %ld
vim +769 fs/open.c
750
751 int chown_common(const struct path *path, uid_t user, gid_t group)
752 {
753 struct mnt_idmap *idmap;
754 struct user_namespace *fs_userns;
755 struct inode *inode = path->dentry->d_inode;
756 struct inode *delegated_inode = NULL;
757 int error;
758 struct iattr newattrs;
759 kuid_t uid;
760 kgid_t gid;
761
762 uid = make_kuid(current_user_ns(), user);
763 gid = make_kgid(current_user_ns(), group);
764
765 idmap = mnt_idmap(path->mnt);
766 fs_userns = i_user_ns(inode);
767
768 retry_deleg:
> 769 printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
770 current->comm, inode, atomic_read(&inode->i_count),
771 atomic_long_read(&inode->i_rwsem.owner));
772 newattrs.ia_vfsuid = INVALID_VFSUID;
773 newattrs.ia_vfsgid = INVALID_VFSGID;
774 newattrs.ia_valid = ATTR_CTIME;
775 if ((user != (uid_t)-1) && !setattr_vfsuid(&newattrs, uid))
776 return -EINVAL;
777 if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid))
778 return -EINVAL;
779 printk("DEBUG: [%s] before inode_lock: inode=%p, i_count=%d\n",
780 current->comm, inode, atomic_read(&inode->i_count));
781 error = inode_lock_killable(inode);
782 if (error)
783 return error;
784 printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
785 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), current);
786 if (!S_ISDIR(inode->i_mode))
787 newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV |
788 setattr_should_drop_sgid(idmap, inode);
789 /* Continue to send actual fs values, not the mount values. */
790 error = security_path_chown(
791 path,
792 from_vfsuid(idmap, fs_userns, newattrs.ia_vfsuid),
793 from_vfsgid(idmap, fs_userns, newattrs.ia_vfsgid));
794 if (!error)
795 error = notify_change(idmap, path->dentry, &newattrs,
796 &delegated_inode);
797 printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
798 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), delegated_inode);
799 inode_unlock(inode);
800 printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
801 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner));
802 if (delegated_inode) {
803 printk("DEBUG: [%s] calling break_deleg_wait: inode=%p, i_count=%d, delegated_inode=%p\n",
804 current->comm, inode, atomic_read(&inode->i_count), delegated_inode);
805 error = break_deleg_wait(&delegated_inode);
806 printk("DEBUG: [%s] after break_deleg_wait: inode=%p, i_count=%d, error=%d\n",
807 current->comm, inode, atomic_read(&inode->i_count), error);
808 if (!error)
809 goto retry_deleg;
810 }
811 return error;
812 }
813
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-11-09 12:17 ` kernel test robot
@ 2025-11-09 12:26 ` Philip Li
0 siblings, 0 replies; 26+ messages in thread
From: Philip Li @ 2025-11-09 12:26 UTC (permalink / raw)
To: kernel test robot; +Cc: syzbot, linux-kernel, syzkaller-bugs, oe-kbuild-all
On Sun, Nov 09, 2025 at 08:17:42PM +0800, kernel test robot wrote:
> Hi syzbot,
Sorry, kindly ignore this report.
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on brauner-vfs/vfs.all]
> [also build test WARNING on linus/master v6.18-rc4 next-20251107]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url: https://github.com/intel-lab-lkp/linux/commits/syzbot/Forwarded-PATCH-fs-fix-inode-use-after-free-in-chown_common-delegation-retry/20251109-171000
> base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
> patch link: https://lore.kernel.org/r/691059ff.a70a0220.22f260.00a6.GAE%40google.com
> patch subject: Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
> config: i386-allnoconfig (https://download.01.org/0day-ci/archive/20251109/202511091831.tPcsumuB-lkp@intel.com/config)
> compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251109/202511091831.tPcsumuB-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202511091831.tPcsumuB-lkp@intel.com/
>
> All warnings (new ones prefixed by >>):
>
> In file included from include/asm-generic/bug.h:22,
> from arch/x86/include/asm/bug.h:108,
> from include/linux/bug.h:5,
> from include/linux/mmdebug.h:5,
> from include/linux/mm.h:6,
> from fs/open.c:9:
> fs/open.c: In function 'chown_common':
> >> fs/open.c:769:16: warning: format '%p' expects argument of type 'void *', but argument 5 has type 'long int' [-Wformat=]
> 769 | printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 770 | current->comm, inode, atomic_read(&inode->i_count),
> 771 | atomic_long_read(&inode->i_rwsem.owner));
> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> | |
> | long int
> include/linux/printk.h:484:25: note: in definition of macro 'printk_index_wrap'
> 484 | _p_func(_fmt, ##__VA_ARGS__); \
> | ^~~~
> fs/open.c:769:9: note: in expansion of macro 'printk'
> 769 | printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
> | ^~~~~~
> fs/open.c:769:79: note: format string is defined here
> 769 | printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
> | ~^
> | |
> | void *
> | %ld
> fs/open.c:784:16: warning: format '%p' expects argument of type 'void *', but argument 4 has type 'long int' [-Wformat=]
> 784 | printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 785 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), current);
> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> | |
> | long int
> include/linux/printk.h:484:25: note: in definition of macro 'printk_index_wrap'
> 484 | _p_func(_fmt, ##__VA_ARGS__); \
> | ^~~~
> fs/open.c:784:9: note: in expansion of macro 'printk'
> 784 | printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
> | ^~~~~~
> fs/open.c:784:72: note: format string is defined here
> 784 | printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
> | ~^
> | |
> | void *
> | %ld
> fs/open.c:797:16: warning: format '%p' expects argument of type 'void *', but argument 4 has type 'long int' [-Wformat=]
> 797 | printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 798 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), delegated_inode);
> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> | |
> | long int
> include/linux/printk.h:484:25: note: in definition of macro 'printk_index_wrap'
> 484 | _p_func(_fmt, ##__VA_ARGS__); \
> | ^~~~
> fs/open.c:797:9: note: in expansion of macro 'printk'
> 797 | printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
> | ^~~~~~
> fs/open.c:797:75: note: format string is defined here
> 797 | printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
> | ~^
> | |
> | void *
> | %ld
> fs/open.c:800:16: warning: format '%p' expects argument of type 'void *', but argument 4 has type 'long int' [-Wformat=]
> 800 | printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 801 | current->comm, inode, atomic_long_read(&inode->i_rwsem.owner));
> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> | |
> | long int
> include/linux/printk.h:484:25: note: in definition of macro 'printk_index_wrap'
> 484 | _p_func(_fmt, ##__VA_ARGS__); \
> | ^~~~
> fs/open.c:800:9: note: in expansion of macro 'printk'
> 800 | printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
> | ^~~~~~
> fs/open.c:800:74: note: format string is defined here
> 800 | printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
> | ~^
> | |
> | void *
> | %ld
>
>
> vim +769 fs/open.c
>
> 750
> 751 int chown_common(const struct path *path, uid_t user, gid_t group)
> 752 {
> 753 struct mnt_idmap *idmap;
> 754 struct user_namespace *fs_userns;
> 755 struct inode *inode = path->dentry->d_inode;
> 756 struct inode *delegated_inode = NULL;
> 757 int error;
> 758 struct iattr newattrs;
> 759 kuid_t uid;
> 760 kgid_t gid;
> 761
> 762 uid = make_kuid(current_user_ns(), user);
> 763 gid = make_kgid(current_user_ns(), group);
> 764
> 765 idmap = mnt_idmap(path->mnt);
> 766 fs_userns = i_user_ns(inode);
> 767
> 768 retry_deleg:
> > 769 printk("DEBUG: [%s] retry_deleg: inode=%p, i_count=%d, i_rwsem.owner=%px\n",
> 770 current->comm, inode, atomic_read(&inode->i_count),
> 771 atomic_long_read(&inode->i_rwsem.owner));
> 772 newattrs.ia_vfsuid = INVALID_VFSUID;
> 773 newattrs.ia_vfsgid = INVALID_VFSGID;
> 774 newattrs.ia_valid = ATTR_CTIME;
> 775 if ((user != (uid_t)-1) && !setattr_vfsuid(&newattrs, uid))
> 776 return -EINVAL;
> 777 if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid))
> 778 return -EINVAL;
> 779 printk("DEBUG: [%s] before inode_lock: inode=%p, i_count=%d\n",
> 780 current->comm, inode, atomic_read(&inode->i_count));
> 781 error = inode_lock_killable(inode);
> 782 if (error)
> 783 return error;
> 784 printk("DEBUG: [%s] after inode_lock: inode=%p, i_rwsem.owner=%px (current=%px)\n",
> 785 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), current);
> 786 if (!S_ISDIR(inode->i_mode))
> 787 newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV |
> 788 setattr_should_drop_sgid(idmap, inode);
> 789 /* Continue to send actual fs values, not the mount values. */
> 790 error = security_path_chown(
> 791 path,
> 792 from_vfsuid(idmap, fs_userns, newattrs.ia_vfsuid),
> 793 from_vfsgid(idmap, fs_userns, newattrs.ia_vfsgid));
> 794 if (!error)
> 795 error = notify_change(idmap, path->dentry, &newattrs,
> 796 &delegated_inode);
> 797 printk("DEBUG: [%s] before inode_unlock: inode=%p, i_rwsem.owner=%px, delegated_inode=%p\n",
> 798 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner), delegated_inode);
> 799 inode_unlock(inode);
> 800 printk("DEBUG: [%s] after inode_unlock: inode=%p, i_rwsem.owner=%px\n",
> 801 current->comm, inode, atomic_long_read(&inode->i_rwsem.owner));
> 802 if (delegated_inode) {
> 803 printk("DEBUG: [%s] calling break_deleg_wait: inode=%p, i_count=%d, delegated_inode=%p\n",
> 804 current->comm, inode, atomic_read(&inode->i_count), delegated_inode);
> 805 error = break_deleg_wait(&delegated_inode);
> 806 printk("DEBUG: [%s] after break_deleg_wait: inode=%p, i_count=%d, error=%d\n",
> 807 current->comm, inode, atomic_read(&inode->i_count), error);
> 808 if (!error)
> 809 goto retry_deleg;
> 810 }
> 811 return error;
> 812 }
> 813
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
` (4 preceding siblings ...)
2025-11-09 9:08 ` Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry syzbot
@ 2025-11-09 11:40 ` syzbot
2025-11-09 11:57 ` syzbot
` (4 subsequent siblings)
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-11-09 11:40 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
The chown_common() function has a use-after-free bug in its delegation
retry path. When break_deleg_wait() is called, it internally calls
iput() on the delegated inode, potentially freeing it if this was the
last reference. However, chown_common() continues using the stale inode
pointer on retry, leading to operations on freed memory.
This manifests as a rwsem warning where the inode's rwsem owner field
is corrupted:
DEBUG_RWSEMS_WARN_ON: owner = 0x0
The bug is triggered by concurrent fchownat() calls and is reproducible
on GFS2 filesystems where delegations are common.
Fix by:
1. Re-fetching inode from path->dentry->d_inode on each retry iteration
2. Holding an explicit inode reference with ihold() at iteration start
3. Releasing the reference with iput() on all exit paths
This ensures the inode remains valid throughout delegation break and
retry.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/open.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..9d0f88ce56f9 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -790,6 +790,14 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
if (!error)
error = notify_change(idmap, path->dentry, &newattrs,
&delegated_inode);
+ if (atomic_long_read(&inode->i_rwsem.owner) != (long)current) {
+ printk(KERN_ERR "BUG: About to unlock rwsem we don't own!\n");
+ printk(KERN_ERR " inode=%p\n", inode);
+ printk(KERN_ERR " i_rwsem.owner=%lx\n", atomic_long_read(&inode->i_rwsem.owner));
+ printk(KERN_ERR " current=%p\n", current);
+ printk(KERN_ERR " delegated_inode=%p\n", delegated_inode);
+ dump_stack();
+ }
inode_unlock(inode);
if (delegated_inode) {
error = break_deleg_wait(&delegated_inode);
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
` (5 preceding siblings ...)
2025-11-09 11:40 ` syzbot
@ 2025-11-09 11:57 ` syzbot
2025-11-09 12:25 ` syzbot
` (3 subsequent siblings)
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-11-09 11:57 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
Author: kartikey406@gmail.com
#syz test git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
The chown_common() function has a use-after-free bug in its delegation
retry path. When break_deleg_wait() is called, it internally calls
iput() on the delegated inode, potentially freeing it if this was the
last reference. However, chown_common() continues using the stale inode
pointer on retry, leading to operations on freed memory.
This manifests as a rwsem warning where the inode's rwsem owner field
is corrupted:
DEBUG_RWSEMS_WARN_ON: owner = 0x0
The bug is triggered by concurrent fchownat() calls and is reproducible
on GFS2 filesystems where delegations are common.
Fix by:
1. Re-fetching inode from path->dentry->d_inode on each retry iteration
2. Holding an explicit inode reference with ihold() at iteration start
3. Releasing the reference with iput() on all exit paths
This ensures the inode remains valid throughout delegation break and
retry.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/open.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..9d0f88ce56f9 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -790,6 +790,14 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
if (!error)
error = notify_change(idmap, path->dentry, &newattrs,
&delegated_inode);
+ if (atomic_long_read(&inode->i_rwsem.owner) != (long)current) {
+ printk(KERN_ERR "BUG: About to unlock rwsem we don't own!\n");
+ printk(KERN_ERR " inode=%p\n", inode);
+ printk(KERN_ERR " i_rwsem.owner=%lx\n", atomic_long_read(&inode->i_rwsem.owner));
+ printk(KERN_ERR " current=%p\n", current);
+ printk(KERN_ERR " delegated_inode=%p\n", delegated_inode);
+ dump_stack();
+ }
inode_unlock(inode);
if (delegated_inode) {
error = break_deleg_wait(&delegated_inode);
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
` (6 preceding siblings ...)
2025-11-09 11:57 ` syzbot
@ 2025-11-09 12:25 ` syzbot
2025-11-09 13:27 ` syzbot
` (2 subsequent siblings)
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-11-09 12:25 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
Author: kartikey406@gmail.com
#syz test git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
The chown_common() function has a use-after-free bug in its delegation
retry path. When break_deleg_wait() is called, it internally calls
iput() on the delegated inode, potentially freeing it if this was the
last reference. However, chown_common() continues using the stale inode
pointer on retry, leading to operations on freed memory.
This manifests as a rwsem warning where the inode's rwsem owner field
is corrupted:
DEBUG_RWSEMS_WARN_ON: owner = 0x0
The bug is triggered by concurrent fchownat() calls and is reproducible
on GFS2 filesystems where delegations are common.
Fix by:
1. Re-fetching inode from path->dentry->d_inode on each retry iteration
2. Holding an explicit inode reference with ihold() at iteration start
3. Releasing the reference with iput() on all exit paths
This ensures the inode remains valid throughout delegation break and
retry.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/open.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..e5ff4d052f80 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -787,9 +787,21 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
path,
from_vfsuid(idmap, fs_userns, newattrs.ia_vfsuid),
from_vfsgid(idmap, fs_userns, newattrs.ia_vfsgid));
+ printk(KERN_INFO "After security_path_chown: owner=%lx\n",
+ atomic_long_read(&inode->i_rwsem.owner));
if (!error)
error = notify_change(idmap, path->dentry, &newattrs,
&delegated_inode);
+ printk(KERN_INFO "After notify_change: owner=%lx, error=%d\n",
+ atomic_long_read(&inode->i_rwsem.owner), error);
+ if (atomic_long_read(&inode->i_rwsem.owner) != (long)current) {
+ printk(KERN_ERR "BUG: About to unlock rwsem we don't own!\n");
+ printk(KERN_ERR " inode=%p\n", inode);
+ printk(KERN_ERR " i_rwsem.owner=%lx\n", atomic_long_read(&inode->i_rwsem.owner));
+ printk(KERN_ERR " current=%p\n", current);
+ printk(KERN_ERR " delegated_inode=%p\n", delegated_inode);
+ dump_stack();
+ }
inode_unlock(inode);
if (delegated_inode) {
error = break_deleg_wait(&delegated_inode);
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
` (7 preceding siblings ...)
2025-11-09 12:25 ` syzbot
@ 2025-11-09 13:27 ` syzbot
2025-11-09 14:29 ` syzbot
2025-11-09 15:16 ` syzbot
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-11-09 13:27 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
Author: kartikey406@gmail.com
#syz test git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
The chown_common() function has a use-after-free bug in its delegation
retry path. When break_deleg_wait() is called, it internally calls
iput() on the delegated inode, potentially freeing it if this was the
last reference. However, chown_common() continues using the stale inode
pointer on retry, leading to operations on freed memory.
This manifests as a rwsem warning where the inode's rwsem owner field
is corrupted:
DEBUG_RWSEMS_WARN_ON: owner = 0x0
The bug is triggered by concurrent fchownat() calls and is reproducible
on GFS2 filesystems where delegations are common.
Fix by:
1. Re-fetching inode from path->dentry->d_inode on each retry iteration
2. Holding an explicit inode reference with ihold() at iteration start
3. Releasing the reference with iput() on all exit paths
This ensures the inode remains valid throughout delegation break and
retry.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/open.c | 12 ++++++++++++
include/linux/fs.h | 5 +++++
2 files changed, 17 insertions(+)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..e5ff4d052f80 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -787,9 +787,21 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
path,
from_vfsuid(idmap, fs_userns, newattrs.ia_vfsuid),
from_vfsgid(idmap, fs_userns, newattrs.ia_vfsgid));
+ printk(KERN_INFO "After security_path_chown: owner=%lx\n",
+ atomic_long_read(&inode->i_rwsem.owner));
if (!error)
error = notify_change(idmap, path->dentry, &newattrs,
&delegated_inode);
+ printk(KERN_INFO "After notify_change: owner=%lx, error=%d\n",
+ atomic_long_read(&inode->i_rwsem.owner), error);
+ if (atomic_long_read(&inode->i_rwsem.owner) != (long)current) {
+ printk(KERN_ERR "BUG: About to unlock rwsem we don't own!\n");
+ printk(KERN_ERR " inode=%p\n", inode);
+ printk(KERN_ERR " i_rwsem.owner=%lx\n", atomic_long_read(&inode->i_rwsem.owner));
+ printk(KERN_ERR " current=%p\n", current);
+ printk(KERN_ERR " delegated_inode=%p\n", delegated_inode);
+ dump_stack();
+ }
inode_unlock(inode);
if (delegated_inode) {
error = break_deleg_wait(&delegated_inode);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c895146c1444..84f7267aac3d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -987,6 +987,11 @@ static inline __must_check int inode_lock_killable(struct inode *inode)
static inline void inode_unlock(struct inode *inode)
{
+ printk(KERN_INFO "[%d] inode_unlock: inode=%p, owner=%lx, current=%p (%s:%d)\n",
+ count, inode,
+ atomic_long_read(&inode->i_rwsem.owner),
+ current, current->comm, current->pid);
+ dump_stack();
up_write(&inode->i_rwsem);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
` (8 preceding siblings ...)
2025-11-09 13:27 ` syzbot
@ 2025-11-09 14:29 ` syzbot
2025-11-09 15:16 ` syzbot
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-11-09 14:29 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
Author: kartikey406@gmail.com
#syz test git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
The chown_common() function has a use-after-free bug in its delegation
retry path. When break_deleg_wait() is called, it internally calls
iput() on the delegated inode, potentially freeing it if this was the
last reference. However, chown_common() continues using the stale inode
pointer on retry, leading to operations on freed memory.
This manifests as a rwsem warning where the inode's rwsem owner field
is corrupted:
DEBUG_RWSEMS_WARN_ON: owner = 0x0
The bug is triggered by concurrent fchownat() calls and is reproducible
on GFS2 filesystems where delegations are common.
Fix by:
1. Re-fetching inode from path->dentry->d_inode on each retry iteration
2. Holding an explicit inode reference with ihold() at iteration start
3. Releasing the reference with iput() on all exit paths
This ensures the inode remains valid throughout delegation break and
retry.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/open.c | 12 ++++++++++++
include/linux/fs.h | 5 +++++
2 files changed, 17 insertions(+)
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..e5ff4d052f80 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -787,9 +787,21 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
path,
from_vfsuid(idmap, fs_userns, newattrs.ia_vfsuid),
from_vfsgid(idmap, fs_userns, newattrs.ia_vfsgid));
+ printk(KERN_INFO "After security_path_chown: owner=%lx\n",
+ atomic_long_read(&inode->i_rwsem.owner));
if (!error)
error = notify_change(idmap, path->dentry, &newattrs,
&delegated_inode);
+ printk(KERN_INFO "After notify_change: owner=%lx, error=%d\n",
+ atomic_long_read(&inode->i_rwsem.owner), error);
+ if (atomic_long_read(&inode->i_rwsem.owner) != (long)current) {
+ printk(KERN_ERR "BUG: About to unlock rwsem we don't own!\n");
+ printk(KERN_ERR " inode=%p\n", inode);
+ printk(KERN_ERR " i_rwsem.owner=%lx\n", atomic_long_read(&inode->i_rwsem.owner));
+ printk(KERN_ERR " current=%p\n", current);
+ printk(KERN_ERR " delegated_inode=%p\n", delegated_inode);
+ dump_stack();
+ }
inode_unlock(inode);
if (delegated_inode) {
error = break_deleg_wait(&delegated_inode);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c895146c1444..005586e26688 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -987,6 +987,11 @@ static inline __must_check int inode_lock_killable(struct inode *inode)
static inline void inode_unlock(struct inode *inode)
{
+ printk(KERN_INFO "inode_unlock: inode=%p, owner=%lx, current=%p (%s:%d)\n",
+ inode,
+ atomic_long_read(&inode->i_rwsem.owner),
+ current, current->comm, current->pid);
+ dump_stack();
up_write(&inode->i_rwsem);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Forwarded: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
2025-10-12 5:45 [syzbot] [gfs2?] WARNING in chown_common syzbot
` (9 preceding siblings ...)
2025-11-09 14:29 ` syzbot
@ 2025-11-09 15:16 ` syzbot
10 siblings, 0 replies; 26+ messages in thread
From: syzbot @ 2025-11-09 15:16 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] fs: fix inode use-after-free in chown_common delegation retry
Author: kartikey406@gmail.com
#syz test git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
The chown_common() function has a use-after-free bug in its delegation
retry path. When break_deleg_wait() is called, it internally calls
iput() on the delegated inode, potentially freeing it if this was the
last reference. However, chown_common() continues using the stale inode
pointer on retry, leading to operations on freed memory.
This manifests as a rwsem warning where the inode's rwsem owner field
is corrupted:
DEBUG_RWSEMS_WARN_ON: owner = 0x0
The bug is triggered by concurrent fchownat() calls and is reproducible
on GFS2 filesystems where delegations are common.
Fix by:
1. Re-fetching inode from path->dentry->d_inode on each retry iteration
2. Holding an explicit inode reference with ihold() at iteration start
3. Releasing the reference with iput() on all exit paths
This ensures the inode remains valid throughout delegation break and
retry.
Reported-by: syzbot+04c2672c56fbb9401640@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c2672c56fbb9401640
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
fs/attr.c | 5 ++++-
fs/open.c | 12 ++++++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/fs/attr.c b/fs/attr.c
index 795f231d00e8..a45d29032283 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -418,6 +418,8 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr, struct inode **delegated_inode)
{
struct inode *inode = dentry->d_inode;
+ printk(KERN_INFO "notify_change START: inode=%p, owner=%lx\n",
+ inode, atomic_long_read(&inode->i_rwsem.owner));
umode_t mode = inode->i_mode;
int error;
struct timespec64 now;
@@ -551,7 +553,8 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
fsnotify_change(dentry, ia_valid);
security_inode_post_setattr(idmap, dentry, ia_valid);
}
-
+ printk(KERN_INFO "notify_change END: inode=%p, owner=%lx, error=%d\n",
+ inode, atomic_long_read(&inode->i_rwsem.owner), error);
return error;
}
EXPORT_SYMBOL(notify_change);
diff --git a/fs/open.c b/fs/open.c
index 3d64372ecc67..e5ff4d052f80 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -787,9 +787,21 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
path,
from_vfsuid(idmap, fs_userns, newattrs.ia_vfsuid),
from_vfsgid(idmap, fs_userns, newattrs.ia_vfsgid));
+ printk(KERN_INFO "After security_path_chown: owner=%lx\n",
+ atomic_long_read(&inode->i_rwsem.owner));
if (!error)
error = notify_change(idmap, path->dentry, &newattrs,
&delegated_inode);
+ printk(KERN_INFO "After notify_change: owner=%lx, error=%d\n",
+ atomic_long_read(&inode->i_rwsem.owner), error);
+ if (atomic_long_read(&inode->i_rwsem.owner) != (long)current) {
+ printk(KERN_ERR "BUG: About to unlock rwsem we don't own!\n");
+ printk(KERN_ERR " inode=%p\n", inode);
+ printk(KERN_ERR " i_rwsem.owner=%lx\n", atomic_long_read(&inode->i_rwsem.owner));
+ printk(KERN_ERR " current=%p\n", current);
+ printk(KERN_ERR " delegated_inode=%p\n", delegated_inode);
+ dump_stack();
+ }
inode_unlock(inode);
if (delegated_inode) {
error = break_deleg_wait(&delegated_inode);
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread