Blob Blame History Raw
From 7deee77b993a2234acb123b8ec477bd56f2e3be3 Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Thu, 12 Oct 2023 23:14:23 +0200
Subject: [PATCH] f2fs: Avoid reading renamed directory if parent does not
 change
Git-commit: 7deee77b993a2234acb123b8ec477bd56f2e3be3
Patch-mainline: v6.8-rc1
References: bsc#1221044 CVE-2023-52591

The VFS will not be locking moved directory if its parent does not
change.  Change f2fs rename code to avoid reading renamed directory if
its parent does not change.  Having it uninlined while we are reading
it would cause trouble and we won't be able to rely upon ->i_rwsem
on the directory being renamed in cases that do not alter its parent.

Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Jan Kara <jack@suse.cz>

---
 fs/f2fs/namei.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -657,6 +657,7 @@ static int f2fs_rename(struct inode *old
 	struct f2fs_dir_entry *old_dir_entry = NULL;
 	struct f2fs_dir_entry *old_entry;
 	struct f2fs_dir_entry *new_entry;
+	bool old_is_dir = S_ISDIR(old_inode->i_mode);
 	bool is_old_inline = f2fs_has_inline_dentry(old_dir);
 	int err = -ENOENT;
 
@@ -679,7 +680,7 @@ static int f2fs_rename(struct inode *old
 		goto out;
 	}
 
-	if (S_ISDIR(old_inode->i_mode)) {
+	if (old_is_dir && old_dir != new_dir) {
 		old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
 		if (!old_dir_entry) {
 			if (IS_ERR(old_dir_page))
@@ -697,7 +698,7 @@ static int f2fs_rename(struct inode *old
 	if (new_inode) {
 
 		err = -ENOTEMPTY;
-		if (old_dir_entry && !f2fs_empty_dir(new_inode))
+		if (old_is_dir && !f2fs_empty_dir(new_inode))
 			goto out_whiteout;
 
 		err = -ENOENT;
@@ -721,7 +722,7 @@ static int f2fs_rename(struct inode *old
 
 		new_inode->i_ctime = current_time(new_inode);
 		down_write(&F2FS_I(new_inode)->i_sem);
-		if (old_dir_entry)
+		if (old_is_dir)
 			f2fs_i_links_write(new_inode, false);
 		f2fs_i_links_write(new_inode, false);
 		up_write(&F2FS_I(new_inode)->i_sem);
@@ -741,7 +742,7 @@ static int f2fs_rename(struct inode *old
 			goto out_whiteout;
 		}
 
-		if (old_dir_entry)
+		if (old_is_dir)
 			f2fs_i_links_write(new_dir, true);
 
 		/*
@@ -786,8 +787,8 @@ static int f2fs_rename(struct inode *old
 		iput(whiteout);
 	}
 
-	if (old_dir_entry) {
-		if (old_dir != new_dir && !whiteout) {
+	if (old_is_dir) {
+		if (old_dir_entry && !whiteout) {
 			f2fs_set_link(old_inode, old_dir_entry,
 						old_dir_page, new_dir);
 		} else {