diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index a92eb79de0cc7fedd2f53cc369348846396e24f3..dce229183b014615cc61cd09cd1bc61f26c8cc0a 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c @@ -261,7 +261,10 @@ static int __ext4fs_dirhash(const char *name, int len, break; default: hinfo->hash = 0; - return -1; + hinfo->minor_hash = 0; + pr_warn("invalid/unsupported hash tree version %u", + hinfo->hash_version); + return -EINVAL; } hash = hash & ~1; if (hash == (EXT4_HTREE_EOF_32BIT << 1)) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 243a2a23015e8ac2287ddf5dceccc4a6cacf21e3..412af3c5fde4fbbaa76be169b79bf9d8140f526d 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -5137,9 +5137,12 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, "iget: bogus i_mode (%o)", inode->i_mode); goto bad_inode; } - if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb)) + if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb)) { ext4_error_inode(inode, function, line, 0, "casefold flag without casefold feature"); + ret = -EFSCORRUPTED; + goto bad_inode; + } if ((err_str = check_igot_inode(inode, flags)) != NULL) { ext4_error_inode(inode, function, line, 0, err_str); ret = -EFSCORRUPTED; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 4c2162ef63ec4cd778b2b5440c2bb3f596390706..4f1db44acd1ccffb9a8af92fb4207d56e356594d 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -681,7 +681,7 @@ static struct stats dx_show_leaf(struct inode *dir, } if (!fscrypt_has_encryption_key(dir)) { /* Directory is not encrypted */ - ext4fs_dirhash(dir, de->name, + (void) ext4fs_dirhash(dir, de->name, de->name_len, &h); printk("%*.s:(U)%x.%u ", len, name, h.hash, @@ -713,8 +713,9 @@ static struct stats dx_show_leaf(struct inode *dir, name = fname_crypto_str.name; len = fname_crypto_str.len; } - ext4fs_dirhash(dir, de->name, - de->name_len, &h); + (void) ext4fs_dirhash(dir, + de->name, + de->name_len, &h); printk("%*.s:(E)%x.%u ", len, name, h.hash, (unsigned) ((char *) de - base)); @@ -724,7 +725,8 @@ static struct stats dx_show_leaf(struct inode *dir, #else int len = de->name_len; char *name = de->name; - ext4fs_dirhash(dir, de->name, de->name_len, &h); + (void) ext4fs_dirhash(dir, de->name, + de->name_len, &h); printk("%*.s:%x.%u ", len, name, h.hash, (unsigned) ((char *) de - base)); #endif @@ -814,8 +816,14 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, if (hinfo->hash_version <= DX_HASH_TEA) hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; - if (fname && fname_name(fname)) - ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), hinfo); + if (fname && fname_name(fname)) { + int ret = ext4fs_dirhash(dir, fname_name(fname), + fname_len(fname), hinfo); + if (ret < 0) { + ret_err = ERR_PTR(ret); + goto fail; + } + } hash = hinfo->hash; if (root->info.unused_flags & 1) { @@ -1077,7 +1085,12 @@ static int htree_dirblock_to_tree(struct file *dir_file, /* silently ignore the rest of the block */ break; } - ext4fs_dirhash(dir, de->name, de->name_len, hinfo); + err = ext4fs_dirhash(dir, de->name, + de->name_len, hinfo); + if (err < 0) { + count = err; + goto errout; + } if ((hinfo->hash < start_hash) || ((hinfo->hash == start_hash) && (hinfo->minor_hash < start_minor_hash))) @@ -1273,7 +1286,10 @@ static int dx_make_map(struct inode *dir, struct buffer_head *bh, ((char *)de) - base)) return -EFSCORRUPTED; if (de->name_len && de->inode) { - ext4fs_dirhash(dir, de->name, de->name_len, &h); + int err = ext4fs_dirhash(dir, de->name, + de->name_len, &h); + if (err < 0) + return err; map_tail--; map_tail->hash = h.hash; map_tail->offs = ((char *) de - base)>>2; @@ -2202,7 +2218,13 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, if (fname->hinfo.hash_version <= DX_HASH_TEA) fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; - ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), &fname->hinfo); + retval = ext4fs_dirhash(dir, fname_name(fname), + fname_len(fname), &fname->hinfo); + if (retval < 0) { + brelse(bh2); + brelse(bh); + return retval; + } memset(frames, 0, sizeof(frames)); frame = frames;