summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2019-09-03 01:43:17 -0400
committerTheodore Ts'o <tytso@mit.edu>2019-09-03 01:43:17 -0400
commit6456ca6520ab6c9aec589b4640169cd6da378c68 (patch)
treefd571eddedc34f63bc84e72e6c6c190ec0056be0
parent9ba55543fc0c6bb1cf8edd63be8802d9ab7e1202 (diff)
ext4: fix kernel oops caused by spurious casefold flag
If an directory has the a casefold flag set without the casefold feature set, s_encoding will not be initialized, and this will cause the kernel to dereference a NULL pointer. In addition to adding checks to avoid these kernel oops, attempts to load inodes with the casefold flag when the casefold feature is not enable will cause the file system to be declared corrupted. Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--fs/ext4/dir.c7
-rw-r--r--fs/ext4/hash.c2
-rw-r--r--fs/ext4/inode.c3
-rw-r--r--fs/ext4/namei.c4
4 files changed, 10 insertions, 6 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 86054f31fe4d..9fdd2b269d61 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -668,14 +668,15 @@ static int ext4_d_compare(const struct dentry *dentry, unsigned int len,
668 const char *str, const struct qstr *name) 668 const char *str, const struct qstr *name)
669{ 669{
670 struct qstr qstr = {.name = str, .len = len }; 670 struct qstr qstr = {.name = str, .len = len };
671 struct inode *inode = dentry->d_parent->d_inode;
671 672
672 if (!IS_CASEFOLDED(dentry->d_parent->d_inode)) { 673 if (!IS_CASEFOLDED(inode) || !EXT4_SB(inode->i_sb)->s_encoding) {
673 if (len != name->len) 674 if (len != name->len)
674 return -1; 675 return -1;
675 return memcmp(str, name->name, len); 676 return memcmp(str, name->name, len);
676 } 677 }
677 678
678 return ext4_ci_compare(dentry->d_parent->d_inode, name, &qstr, false); 679 return ext4_ci_compare(inode, name, &qstr, false);
679} 680}
680 681
681static int ext4_d_hash(const struct dentry *dentry, struct qstr *str) 682static int ext4_d_hash(const struct dentry *dentry, struct qstr *str)
@@ -685,7 +686,7 @@ static int ext4_d_hash(const struct dentry *dentry, struct qstr *str)
685 unsigned char *norm; 686 unsigned char *norm;
686 int len, ret = 0; 687 int len, ret = 0;
687 688
688 if (!IS_CASEFOLDED(dentry->d_inode)) 689 if (!IS_CASEFOLDED(dentry->d_inode) || !um)
689 return 0; 690 return 0;
690 691
691 norm = kmalloc(PATH_MAX, GFP_ATOMIC); 692 norm = kmalloc(PATH_MAX, GFP_ATOMIC);
diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c
index d358bfcb6b3f..3e133793a5a3 100644
--- a/fs/ext4/hash.c
+++ b/fs/ext4/hash.c
@@ -280,7 +280,7 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
280 unsigned char *buff; 280 unsigned char *buff;
281 struct qstr qstr = {.name = name, .len = len }; 281 struct qstr qstr = {.name = name, .len = len };
282 282
283 if (len && IS_CASEFOLDED(dir)) { 283 if (len && IS_CASEFOLDED(dir) && um) {
284 buff = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL); 284 buff = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL);
285 if (!buff) 285 if (!buff)
286 return -ENOMEM; 286 return -ENOMEM;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index e567f0229d4e..4e271b509af1 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -5067,6 +5067,9 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
5067 "iget: bogus i_mode (%o)", inode->i_mode); 5067 "iget: bogus i_mode (%o)", inode->i_mode);
5068 goto bad_inode; 5068 goto bad_inode;
5069 } 5069 }
5070 if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb))
5071 ext4_error_inode(inode, function, line, 0,
5072 "casefold flag without casefold feature");
5070 brelse(iloc.bh); 5073 brelse(iloc.bh);
5071 5074
5072 unlock_new_inode(inode); 5075 unlock_new_inode(inode);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 129029534075..a427d2031a8d 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1312,7 +1312,7 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
1312{ 1312{
1313 int len; 1313 int len;
1314 1314
1315 if (!IS_CASEFOLDED(dir)) { 1315 if (!IS_CASEFOLDED(dir) || !EXT4_SB(dir->i_sb)->s_encoding) {
1316 cf_name->name = NULL; 1316 cf_name->name = NULL;
1317 return; 1317 return;
1318 } 1318 }
@@ -2183,7 +2183,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
2183 2183
2184#ifdef CONFIG_UNICODE 2184#ifdef CONFIG_UNICODE
2185 if (ext4_has_strict_mode(sbi) && IS_CASEFOLDED(dir) && 2185 if (ext4_has_strict_mode(sbi) && IS_CASEFOLDED(dir) &&
2186 utf8_validate(sbi->s_encoding, &dentry->d_name)) 2186 sbi->s_encoding && utf8_validate(sbi->s_encoding, &dentry->d_name))
2187 return -EINVAL; 2187 return -EINVAL;
2188#endif 2188#endif
2189 2189