Blob Blame History Raw
From: Jeff Mahoney <jeffm@suse.com>
Subject: reiserfs: add check to detect corrupted directory entry
Patch-mainline: Submitted, reiserfs-devel@vger.kernel.org, 18 Oct 2018
References: bsc#1109818

In reiserfs_rename, we check to ensure that the old directory entry is
pointing to the expected inode but we don't check the new directory
entry or the .. entry.  Typically this isn't a problem, but in the
retry loop we check to see if the entry is pointing to the expected
inode after scheduling and assume that we must repeat the search if
it doesn't match.  If the directory entry has been corrupted, we
will loop forever.

This patch performs the check immediately after performing the search
so that if there is an error, we can return appropriately.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 fs/reiserfs/namei.c | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 97f3fc4fdd79..5be509a9204f 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -1282,7 +1282,7 @@ static int entry_points_to_object(const char *name, int len,
 
 	/* this must be added hidden entry */
 	if (de_visible(de->de_deh + de->de_entry_num))
-		reiserfs_panic(NULL, "vs-7043", "entry must be visible");
+		reiserfs_panic(NULL, "vs-7043", "entry must be invisible");
 
 	return 1;
 }
@@ -1389,7 +1389,8 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		    reiserfs_find_entry(old_inode, "..", 2, &dot_dot_entry_path,
 					&dot_dot_de);
 		pathrelse(&dot_dot_entry_path);
-		if (retval != NAME_FOUND) {
+		if (retval != NAME_FOUND ||
+		    dot_dot_de.de_objectid != old_dir->i_ino) {
 			reiserfs_write_unlock(old_dir->i_sb);
 			return -EIO;
 		}
@@ -1473,6 +1474,33 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			return -EIO;
 		}
 
+		/*
+		 * If this entry is corrupted and points somewhere else,
+		 * we'll loop forever as we check to ensure it points to
+		 * the expected object in the sanity check below.  Since
+		 * we can't have scheduled yet after finding this one,
+		 * check it now so we can bail early.
+		 */
+		if (new_dentry_inode &&
+		    new_de.de_objectid != new_dentry_inode->i_ino) {
+			struct reiserfs_key *key = INODE_PKEY(new_dentry_inode);
+
+			reiserfs_error(old_inode->i_sb, "namei-7055",
+"directory entry for %.*s points to [%u, %u]; expected [%u, %u], ino %lu",
+				       new_dentry->d_name.len,
+				       new_dentry->d_name.name,
+				       new_de.de_dir_id, new_de.de_objectid,
+				       le32_to_cpu(key->k_dir_id),
+				       le32_to_cpu(key->k_objectid),
+				       new_dentry_inode->i_ino);
+
+			pathrelse(&new_entry_path);
+			pathrelse(&old_entry_path);
+			journal_end(&th);
+			reiserfs_write_unlock(old_dir->i_sb);
+			return -EIO;
+		}
+
 		copy_item_head(&new_entry_ih, tp_item_head(&new_entry_path));
 
 		reiserfs_prepare_for_journal(old_inode->i_sb, new_de.de_bh, 1);