Blob Blame History Raw
From 7307b73fa5a82661808b5541972176c344978789 Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Thu, 12 Oct 2023 23:14:22 +0200
Subject: [PATCH] ext2: Avoid reading renamed directory if parent does not
 change
Git-commit: 7307b73fa5a82661808b5541972176c344978789
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 ext2 rename code to avoid reading renamed directory if
its parent does not change. Although it is currently harmless it is a
bad practice to read directory contents without inode->i_rwsem.

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/ext2/namei.c |   15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -321,6 +321,7 @@ static int ext2_rename (struct inode * o
 	struct ext2_dir_entry_2 * dir_de = NULL;
 	struct page * old_page;
 	struct ext2_dir_entry_2 * old_de;
+	bool old_is_dir = S_ISDIR(old_inode->i_mode);
 	int err;
 
 	if (flags & ~RENAME_NOREPLACE)
@@ -340,7 +341,7 @@ static int ext2_rename (struct inode * o
 		goto out;
 	}
 
-	if (S_ISDIR(old_inode->i_mode)) {
+	if (old_is_dir && old_dir != new_dir) {
 		err = -EIO;
 		dir_de = ext2_dotdot(old_inode, &dir_page);
 		if (!dir_de)
@@ -352,7 +353,7 @@ static int ext2_rename (struct inode * o
 		struct ext2_dir_entry_2 *new_de;
 
 		err = -ENOTEMPTY;
-		if (dir_de && !ext2_empty_dir (new_inode))
+		if (old_is_dir && !ext2_empty_dir(new_inode))
 			goto out_dir;
 
 		err = -ENOENT;
@@ -361,14 +362,14 @@ static int ext2_rename (struct inode * o
 			goto out_dir;
 		ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
 		new_inode->i_ctime = current_time(new_inode);
-		if (dir_de)
+		if (old_is_dir)
 			drop_nlink(new_inode);
 		inode_dec_link_count(new_inode);
 	} else {
 		err = ext2_add_link(new_dentry, old_inode);
 		if (err)
 			goto out_dir;
-		if (dir_de)
+		if (old_is_dir)
 			inode_inc_link_count(new_dir);
 	}
 
@@ -381,13 +382,9 @@ static int ext2_rename (struct inode * o
 
 	ext2_delete_entry (old_de, old_page);
 
-	if (dir_de) {
+	if (old_is_dir) {
 		if (old_dir != new_dir)
 			ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0);
-		else {
-			kunmap(dir_page);
-			put_page(dir_page);
-		}
 		inode_dec_link_count(old_dir);
 	}
 	return 0;