* [PATCH 6.1.y 1/2] udf_rename(): only access the child content on cross-directory rename
2025-11-25 11:03 [PATCH 6.1.y 0/2] udf: backport udf_rename fixes to verify link-count Sukrut Heroorkar
@ 2025-11-25 11:03 ` Sukrut Heroorkar
2025-11-25 11:03 ` [PATCH 6.1.y 2/2] udf: Verify inode link counts before performing rename Sukrut Heroorkar
1 sibling, 0 replies; 3+ messages in thread
From: Sukrut Heroorkar @ 2025-11-25 11:03 UTC (permalink / raw)
To: Jan Kara, open list
Cc: shuah, david.hunter.linux, Al Viro, Jan Kara, Sukrut Heroorkar
From: Al Viro <viro@zeniv.linux.org.uk>
[ Upstream commit 9d35cebb794bb7be93db76c3383979c7deacfef9 ]
We can't really afford locking the source on same-directory rename;
currently vfs_rename() tries to do that, but it will have to be
changed. The logics in udf_rename() is lazy and goes looking for
".." in source even in same-directory case. It's not hard to get
rid of that, leaving that behaviour only for cross-directory case;
that VFS can get locks safely (and will keep doing that after the
coming changes).
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Stable-dep-of: 6756af923e06 ("udf: Verify inode link counts before performing rename")
Signed-off-by: Sukrut Heroorkar <hsukrut3@gmail.com>
---
fs/udf/namei.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 29ab5f80dd41..adee216c6769 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -751,7 +751,7 @@ static int udf_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);
struct udf_fileident_iter oiter, niter, diriter;
- bool has_diriter = false;
+ bool has_diriter = false, is_dir = false;
int retval;
struct kernel_lb_addr tloc;
@@ -774,6 +774,9 @@ static int udf_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
if (!empty_dir(new_inode))
goto out_oiter;
}
+ is_dir = true;
+ }
+ if (is_dir && old_dir != new_dir) {
retval = udf_fiiter_find_entry(old_inode, &dotdot_name,
&diriter);
if (retval == -ENOENT) {
@@ -859,7 +862,9 @@ static int udf_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
cpu_to_lelb(UDF_I(new_dir)->i_location);
udf_fiiter_write_fi(&diriter, NULL);
udf_fiiter_release(&diriter);
+ }
+ if (is_dir) {
inode_dec_link_count(old_dir);
if (new_inode)
inode_dec_link_count(new_inode);
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 6.1.y 2/2] udf: Verify inode link counts before performing rename
2025-11-25 11:03 [PATCH 6.1.y 0/2] udf: backport udf_rename fixes to verify link-count Sukrut Heroorkar
2025-11-25 11:03 ` [PATCH 6.1.y 1/2] udf_rename(): only access the child content on cross-directory rename Sukrut Heroorkar
@ 2025-11-25 11:03 ` Sukrut Heroorkar
1 sibling, 0 replies; 3+ messages in thread
From: Sukrut Heroorkar @ 2025-11-25 11:03 UTC (permalink / raw)
To: Jan Kara, open list
Cc: shuah, david.hunter.linux, Jan Kara, syzbot+3ff7365dc04a6bcafa66,
syzbot+72f20dcde8dd7e4a788a, Sukrut Heroorkar
From: Jan Kara <jack@suse.cz>
[ Upstream commit 6756af923e06aa33ad8894aaecbf9060953ba00f ]
During rename, we are updating link counts of various inodes either when
rename deletes target or when moving directory across directories.
Verify involved link counts are sane so that we don't trip warnings in
VFS.
Reported-by: syzbot+3ff7365dc04a6bcafa66@syzkaller.appspotmail.com
Signed-off-by: Jan Kara <jack@suse.cz>
Tested-by: syzbot+72f20dcde8dd7e4a788a@syzkaller.appspotmail.com
Signed-off-by: Sukrut Heroorkar <hsukrut3@gmail.com>
---
fs/udf/namei.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index adee216c6769..5bf074c56cde 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -773,8 +773,18 @@ static int udf_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto out_oiter;
+ retval = -EFSCORRUPTED;
+ if (new_inode->i_nlink != 2)
+ goto out_oiter;
}
+ retval = -EFSCORRUPTED;
+ if (old_dir->i_nlink < 3)
+ goto out_oiter;
is_dir = true;
+ } else if (new_inode) {
+ retval = -EFSCORRUPTED;
+ if (new_inode->i_nlink < 1)
+ goto out_oiter;
}
if (is_dir && old_dir != new_dir) {
retval = udf_fiiter_find_entry(old_inode, &dotdot_name,
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread