fs/open.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
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
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
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
>
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
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
>
© 2016 - 2025 Red Hat, Inc.