Re: [PATCH 2/2] reiserfs: don't panic on bad directory entries

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 10/18/18 3:46 PM, jeffm@xxxxxxxx wrote:
> From: Jeff Mahoney <jeffm@xxxxxxxx>
> 
> If a directory entry has been corrupted such that the flags reflect
> a different visibility state than expected, we will panic the node.
> 
> This patch instead returns -EIO and sets the file system read-only.
> 
> Signed-off-by: Jeff Mahoney <jeffm@xxxxxxxx>
> ---
>  fs/reiserfs/namei.c | 108 ++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 67 insertions(+), 41 deletions(-)
> 
> diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
> index 5be509a9204f..01e788f91a1d 100644
> --- a/fs/reiserfs/namei.c
> +++ b/fs/reiserfs/namei.c
> @@ -1254,7 +1254,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
>  
>  /* de contains information pointing to an entry which */
>  static int de_still_valid(const char *name, int len,
> -			  struct reiserfs_dir_entry *de)
> +			  const struct reiserfs_dir_entry *de)
>  {
>  	struct reiserfs_dir_entry tmp = *de;
>  
> @@ -1266,23 +1266,31 @@ static int de_still_valid(const char *name, int len,
>  	return 1;
>  }
>  
> -static int entry_points_to_object(const char *name, int len,
> -				  struct reiserfs_dir_entry *de,
> -				  struct inode *inode)
> +static int entry_points_to_object(const struct inode *dir,
> +				  const char *name, int len,
> +				  const struct reiserfs_dir_entry *de,
> +				  const struct inode *inode)
>  {
>  	if (!de_still_valid(name, len, de))
>  		return 0;
>  
>  	if (inode) {
> -		if (!de_visible(de->de_deh + de->de_entry_num))
> -			reiserfs_panic(inode->i_sb, "vs-7042",
> -				       "entry must be visible");
> +		if (!de_visible(de->de_deh + de->de_entry_num)) {
> +			reiserfs_error(dir->i_sb, "vs-7042",
> +				       "entry must be visible (%.*s in dir %k",
> +				       len, name, INODE_PKEY(dir));
> +			return -EIO;
> +		}
>  		return (de->de_objectid == inode->i_ino) ? 1 : 0;
>  	}
>  
>  	/* this must be added hidden entry */
> -	if (de_visible(de->de_deh + de->de_entry_num))
> -		reiserfs_panic(NULL, "vs-7043", "entry must be invisible");
> +	if (de_visible(de->de_deh + de->de_entry_num)) {
> +		reiserfs_error(dir->i_sb, "vs-7043",
> +			       "entry must be invisible (%.*s in dir %k",
> +			       len, name, INODE_PKEY(dir));
> +		return -EIO;
> +	}
>  
>  	return 1;
>  }
> @@ -1541,47 +1549,65 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
>  		 * of the above checks could have scheduled.  We have to be
>  		 * sure our items haven't been shifted by another process.
>  		 */
> -		if (item_moved(&new_entry_ih, &new_entry_path) ||
> -		    !entry_points_to_object(new_dentry->d_name.name,
> -					    new_dentry->d_name.len,
> -					    &new_de, new_dentry_inode) ||
> -		    item_moved(&old_entry_ih, &old_entry_path) ||
> -		    !entry_points_to_object(old_dentry->d_name.name,
> -					    old_dentry->d_name.len,
> -					    &old_de, old_inode)) {
> -			reiserfs_restore_prepared_buffer(old_inode->i_sb,
> -							 new_de.de_bh);
> -			reiserfs_restore_prepared_buffer(old_inode->i_sb,
> -							 old_de.de_bh);
> -			if (S_ISDIR(old_inode_mode))
> -				reiserfs_restore_prepared_buffer(old_inode->
> -								 i_sb,
> -								 dot_dot_de.
> -								 de_bh);
> -			continue;
> +		if (item_moved(&new_entry_ih, &new_entry_path)) {
> +			retval = 0;
> +			goto restore;
>  		}
> +
> +		retval = entry_points_to_object(new_dir,
> +						new_dentry->d_name.name,
> +						new_dentry->d_name.len,
> +						&new_de, new_dentry_inode);
> +		if (retval != 1)
> +			goto restore;
> +
> +		if (item_moved(&old_entry_ih, &old_entry_path)) {
> +			retval = 0;
> +			goto restore;
> +		}
> +
> +		retval = entry_points_to_object(old_dir,
> +						old_dentry->d_name.name,
> +						old_dentry->d_name.len,
> +						&old_de, old_inode);
> +		if (retval != 1)
> +			goto restore;
> +
>  		if (S_ISDIR(old_inode_mode)) {
> -			if (item_moved(&dot_dot_ih, &dot_dot_entry_path) ||
> -			    !entry_points_to_object("..", 2, &dot_dot_de,
> -						    old_dir)) {
> -				reiserfs_restore_prepared_buffer(old_inode->
> -								 i_sb,
> -								 old_de.de_bh);
> -				reiserfs_restore_prepared_buffer(old_inode->
> -								 i_sb,
> -								 new_de.de_bh);
> -				reiserfs_restore_prepared_buffer(old_inode->
> -								 i_sb,
> -								 dot_dot_de.
> -								 de_bh);
> -				continue;
> +			if (item_moved(&dot_dot_ih, &dot_dot_entry_path)) {
> +				retval = 0;
> +				goto restore;
>  			}
> +
> +			retval = entry_points_to_object(old_dir, "..", 2,
> +							&dot_dot_de, old_dir);
> +			if (retval != 1)
> +				goto restore;
>  		}
>  
> +		retval = 0;
> +
>  		RFALSE(S_ISDIR(old_inode_mode) &&
>  		       !buffer_journal_prepared(dot_dot_de.de_bh), "");
>  
>  		break;
> +
> +restore:
> +		reiserfs_restore_prepared_buffer(old_inode->i_sb,
> +						 new_de.de_bh);
> +		reiserfs_restore_prepared_buffer(old_inode->i_sb,
> +						 old_de.de_bh);
> +		if (S_ISDIR(old_inode_mode))
> +			reiserfs_restore_prepared_buffer(old_inode->i_sb,
> +							 dot_dot_de.de_bh);
> +		if (retval) {
> +			pathrelse(&dot_dot_entry_path);
> +			pathrelse(&new_entry_path);
> +			pathrelse(&old_entry_path);
> +			journal_end(&th, old_dir->i_sb, jbegin_count);


Well that's not gonna work...

-Jeff

> +			reiserfs_write_unlock(old_dir->i_sb);
> +			return retval;
> +		}
>  	}
>  
>  	/*
> 

-- 
Jeff Mahoney
SUSE Labs


Attachment: signature.asc
Description: OpenPGP digital signature


[Index of Archives]     [Linux File System Development]     [Linux BTRFS]     [Linux NFS]     [Linux Filesystems]     [Ext4 Filesystem]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Resources]

  Powered by Linux