Re: [PATCH 3/5] xfs_db: fix metadump name obfuscation for ascii-ci filesystems

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

 



On Mon, Jun 05, 2023 at 08:36:44AM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@xxxxxxxxxx>
> 
> Now that we've stabilized the dirent hash function for ascii-ci
> filesystems, adapt the metadump name obfuscation code to detect when
> it's obfuscating a directory entry name on an ascii-ci filesystem and
> spit out names that actually have the same hash.
> 
> Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>
> ---
>  db/metadump.c |   77 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 68 insertions(+), 9 deletions(-)
> 
> 
> diff --git a/db/metadump.c b/db/metadump.c
> index 317ff72802d..4f8b3adb163 100644
> --- a/db/metadump.c
> +++ b/db/metadump.c
> @@ -817,13 +817,17 @@ static void
>  obfuscate_name(
>  	xfs_dahash_t	hash,
>  	size_t		name_len,
> -	unsigned char	*name)
> +	unsigned char	*name,
> +	bool		is_dirent)
>  {
> -	unsigned char	*newp = name;
> +	unsigned char	*oldname = NULL;
> +	unsigned char	*newp;
>  	int		i;
> -	xfs_dahash_t	new_hash = 0;
> +	xfs_dahash_t	new_hash;
>  	unsigned char	*first;
>  	unsigned char	high_bit;
> +	int		tries = 0;
> +	bool		is_ci_name = is_dirent && xfs_has_asciici(mp);
>  	int		shift;
> 
>  	/*
> @@ -836,6 +840,24 @@ obfuscate_name(
>  	if (name_len < 5)
>  		return;
> 
> +	if (is_ci_name) {
> +		oldname = alloca(name_len);

			  ^^^ This is triggering a warning on build time because
			      the alloca() call is unbounded:

metadump.c: In function ‘obfuscate_name’:
metadump.c:844:13: warning: argument to ‘alloca’ may be too large
[-Walloca-larger-than=]
  844 |   oldname = alloca(name_len);
      |             ^~~~~~

Maybe just use malloc() here, instead of using stack space? We probably can use
MAXNAMELEN here to bound it, something like:

if (is_ci_name && name_len <= MAXNAMELEN) {
	oldname = alloca(name_len);
	memcpy(oldname, name, name_len);
} else {
	return;
}

-- 
Carlos
> +		memcpy(oldname, name, name_len);
> +	}
> +
> +again:
> +	newp = name;
> +	new_hash = 0;
> +
> +	/*
> +	 * If we cannot generate a ci-compatible obfuscated name after 1000
> +	 * tries, don't bother obfuscating the name.
> +	 */
> +	if (tries++ > 1000) {
> +		memcpy(name, oldname, name_len);
> +		return;
> +	}
> +
>  	/*
>  	 * The beginning of the obfuscated name can be pretty much
>  	 * anything, so fill it in with random characters.
> @@ -843,7 +865,11 @@ obfuscate_name(
>  	 */
>  	for (i = 0; i < name_len - 5; i++) {
>  		*newp = random_filename_char();
> -		new_hash = *newp ^ rol32(new_hash, 7);
> +		if (is_ci_name)
> +			new_hash = xfs_ascii_ci_xfrm(*newp) ^
> +							rol32(new_hash, 7);
> +		else
> +			new_hash = *newp ^ rol32(new_hash, 7);
>  		newp++;
>  	}
> 
> @@ -867,6 +893,17 @@ obfuscate_name(
>  			high_bit = 0x80;
>  		} else
>  			high_bit = 0;
> +
> +		/*
> +		 * If ascii-ci is enabled, uppercase characters are converted
> +		 * to lowercase characters while computing the name hash.  If
> +		 * any of the necessary correction bytes are uppercase, the
> +		 * hash of the new name will not match.  Try again with a
> +		 * different prefix.
> +		 */
> +		if (is_ci_name && xfs_ascii_ci_need_xfrm(*newp))
> +			goto again;
> +
>  		ASSERT(!is_invalid_char(*newp));
>  		newp++;
>  	}
> @@ -880,6 +917,10 @@ obfuscate_name(
>  	 */
>  	if (high_bit) {
>  		*first ^= 0x10;
> +
> +		if (is_ci_name && xfs_ascii_ci_need_xfrm(*first))
> +			goto again;
> +
>  		ASSERT(!is_invalid_char(*first));
>  	}
>  }
> @@ -1177,6 +1218,24 @@ handle_duplicate_name(xfs_dahash_t hash, size_t name_len, unsigned char *name)
>  	return 1;
>  }
> 
> +static inline xfs_dahash_t
> +dirattr_hashname(
> +	bool		is_dirent,
> +	const uint8_t	*name,
> +	int		namelen)
> +{
> +	if (is_dirent) {
> +		struct xfs_name	xname = {
> +			.name	= name,
> +			.len	= namelen,
> +		};
> +
> +		return libxfs_dir2_hashname(mp, &xname);
> +	}
> +
> +	return libxfs_da_hashname(name, namelen);
> +}
> +
>  static void
>  generate_obfuscated_name(
>  	xfs_ino_t		ino,
> @@ -1205,9 +1264,9 @@ generate_obfuscated_name(
> 
>  	/* Obfuscate the name (if possible) */
> 
> -	hash = libxfs_da_hashname(name, namelen);
> -	obfuscate_name(hash, namelen, name);
> -	ASSERT(hash == libxfs_da_hashname(name, namelen));
> +	hash = dirattr_hashname(ino != 0, name, namelen);
> +	obfuscate_name(hash, namelen, name, ino != 0);
> +	ASSERT(hash == dirattr_hashname(ino != 0, name, namelen));
> 
>  	/*
>  	 * Make sure the name is not something already seen.  If we
> @@ -1320,7 +1379,7 @@ obfuscate_path_components(
>  			/* last (or single) component */
>  			namelen = strnlen((char *)comp, len);
>  			hash = libxfs_da_hashname(comp, namelen);
> -			obfuscate_name(hash, namelen, comp);
> +			obfuscate_name(hash, namelen, comp, false);
>  			ASSERT(hash == libxfs_da_hashname(comp, namelen));
>  			break;
>  		}
> @@ -1332,7 +1391,7 @@ obfuscate_path_components(
>  			continue;
>  		}
>  		hash = libxfs_da_hashname(comp, namelen);
> -		obfuscate_name(hash, namelen, comp);
> +		obfuscate_name(hash, namelen, comp, false);
>  		ASSERT(hash == libxfs_da_hashname(comp, namelen));
>  		comp += namelen + 1;
>  		len -= namelen + 1;
> 



[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux