aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/dir.c40
-rw-r--r--fs/ext4/ext4.h3
-rw-r--r--fs/ext4/namei.c14
3 files changed, 32 insertions, 25 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index ece76fb6a40c..bd5d74d06399 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -60,7 +60,11 @@ static unsigned char get_dtype(struct super_block *sb, int filetype)
60 return (ext4_filetype_table[filetype]); 60 return (ext4_filetype_table[filetype]);
61} 61}
62 62
63 63/*
64 * Return 0 if the directory entry is OK, and 1 if there is a problem
65 *
66 * Note: this is the opposite of what ext2 and ext3 historically returned...
67 */
64int __ext4_check_dir_entry(const char *function, unsigned int line, 68int __ext4_check_dir_entry(const char *function, unsigned int line,
65 struct inode *dir, 69 struct inode *dir,
66 struct ext4_dir_entry_2 *de, 70 struct ext4_dir_entry_2 *de,
@@ -71,26 +75,28 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
71 const int rlen = ext4_rec_len_from_disk(de->rec_len, 75 const int rlen = ext4_rec_len_from_disk(de->rec_len,
72 dir->i_sb->s_blocksize); 76 dir->i_sb->s_blocksize);
73 77
74 if (rlen < EXT4_DIR_REC_LEN(1)) 78 if (unlikely(rlen < EXT4_DIR_REC_LEN(1)))
75 error_msg = "rec_len is smaller than minimal"; 79 error_msg = "rec_len is smaller than minimal";
76 else if (rlen % 4 != 0) 80 else if (unlikely(rlen % 4 != 0))
77 error_msg = "rec_len % 4 != 0"; 81 error_msg = "rec_len % 4 != 0";
78 else if (rlen < EXT4_DIR_REC_LEN(de->name_len)) 82 else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
79 error_msg = "rec_len is too small for name_len"; 83 error_msg = "rec_len is too small for name_len";
80 else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) 84 else if (unlikely(((char *) de - bh->b_data) + rlen >
85 dir->i_sb->s_blocksize))
81 error_msg = "directory entry across blocks"; 86 error_msg = "directory entry across blocks";
82 else if (le32_to_cpu(de->inode) > 87 else if (unlikely(le32_to_cpu(de->inode) >
83 le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)) 88 le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)))
84 error_msg = "inode out of bounds"; 89 error_msg = "inode out of bounds";
90 else
91 return 0;
85 92
86 if (error_msg != NULL) 93 ext4_error_inode(dir, function, line, bh->b_blocknr,
87 ext4_error_inode(dir, function, line, bh->b_blocknr, 94 "bad entry in directory: %s - "
88 "bad entry in directory: %s - " 95 "offset=%u(%u), inode=%u, rec_len=%d, name_len=%d",
89 "offset=%u(%u), inode=%u, rec_len=%d, name_len=%d", 96 error_msg, (unsigned) (offset%bh->b_size), offset,
90 error_msg, (unsigned) (offset%bh->b_size), offset, 97 le32_to_cpu(de->inode),
91 le32_to_cpu(de->inode), 98 rlen, de->name_len);
92 rlen, de->name_len); 99 return 1;
93 return error_msg == NULL ? 1 : 0;
94} 100}
95 101
96static int ext4_readdir(struct file *filp, 102static int ext4_readdir(struct file *filp,
@@ -194,8 +200,8 @@ revalidate:
194 while (!error && filp->f_pos < inode->i_size 200 while (!error && filp->f_pos < inode->i_size
195 && offset < sb->s_blocksize) { 201 && offset < sb->s_blocksize) {
196 de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); 202 de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
197 if (!ext4_check_dir_entry(inode, de, 203 if (ext4_check_dir_entry(inode, de,
198 bh, offset)) { 204 bh, offset)) {
199 /* 205 /*
200 * On error, skip the f_pos to the next block 206 * On error, skip the f_pos to the next block
201 */ 207 */
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 17baecbf8cda..49f1ceaac57d 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1639,7 +1639,8 @@ extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
1639 struct ext4_dir_entry_2 *, 1639 struct ext4_dir_entry_2 *,
1640 struct buffer_head *, unsigned int); 1640 struct buffer_head *, unsigned int);
1641#define ext4_check_dir_entry(dir, de, bh, offset) \ 1641#define ext4_check_dir_entry(dir, de, bh, offset) \
1642 __ext4_check_dir_entry(__func__, __LINE__, (dir), (de), (bh), (offset)) 1642 unlikely(__ext4_check_dir_entry(__func__, __LINE__, (dir), (de), \
1643 (bh), (offset)))
1643extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, 1644extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
1644 __u32 minor_hash, 1645 __u32 minor_hash,
1645 struct ext4_dir_entry_2 *dirent); 1646 struct ext4_dir_entry_2 *dirent);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 203086498caa..e275464f7754 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -581,9 +581,9 @@ static int htree_dirblock_to_tree(struct file *dir_file,
581 dir->i_sb->s_blocksize - 581 dir->i_sb->s_blocksize -
582 EXT4_DIR_REC_LEN(0)); 582 EXT4_DIR_REC_LEN(0));
583 for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { 583 for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
584 if (!ext4_check_dir_entry(dir, de, bh, 584 if (ext4_check_dir_entry(dir, de, bh,
585 (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb)) 585 (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb))
586 +((char *)de - bh->b_data))) { 586 + ((char *)de - bh->b_data))) {
587 /* On error, skip the f_pos to the next block. */ 587 /* On error, skip the f_pos to the next block. */
588 dir_file->f_pos = (dir_file->f_pos | 588 dir_file->f_pos = (dir_file->f_pos |
589 (dir->i_sb->s_blocksize - 1)) + 1; 589 (dir->i_sb->s_blocksize - 1)) + 1;
@@ -820,7 +820,7 @@ static inline int search_dirblock(struct buffer_head *bh,
820 if ((char *) de + namelen <= dlimit && 820 if ((char *) de + namelen <= dlimit &&
821 ext4_match (namelen, name, de)) { 821 ext4_match (namelen, name, de)) {
822 /* found a match - just to be sure, do a full check */ 822 /* found a match - just to be sure, do a full check */
823 if (!ext4_check_dir_entry(dir, de, bh, offset)) 823 if (ext4_check_dir_entry(dir, de, bh, offset))
824 return -1; 824 return -1;
825 *res_dir = de; 825 *res_dir = de;
826 return 1; 826 return 1;
@@ -1269,7 +1269,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
1269 de = (struct ext4_dir_entry_2 *)bh->b_data; 1269 de = (struct ext4_dir_entry_2 *)bh->b_data;
1270 top = bh->b_data + blocksize - reclen; 1270 top = bh->b_data + blocksize - reclen;
1271 while ((char *) de <= top) { 1271 while ((char *) de <= top) {
1272 if (!ext4_check_dir_entry(dir, de, bh, offset)) 1272 if (ext4_check_dir_entry(dir, de, bh, offset))
1273 return -EIO; 1273 return -EIO;
1274 if (ext4_match(namelen, name, de)) 1274 if (ext4_match(namelen, name, de))
1275 return -EEXIST; 1275 return -EEXIST;
@@ -1636,7 +1636,7 @@ static int ext4_delete_entry(handle_t *handle,
1636 pde = NULL; 1636 pde = NULL;
1637 de = (struct ext4_dir_entry_2 *) bh->b_data; 1637 de = (struct ext4_dir_entry_2 *) bh->b_data;
1638 while (i < bh->b_size) { 1638 while (i < bh->b_size) {
1639 if (!ext4_check_dir_entry(dir, de, bh, i)) 1639 if (ext4_check_dir_entry(dir, de, bh, i))
1640 return -EIO; 1640 return -EIO;
1641 if (de == de_del) { 1641 if (de == de_del) {
1642 BUFFER_TRACE(bh, "get_write_access"); 1642 BUFFER_TRACE(bh, "get_write_access");
@@ -1919,7 +1919,7 @@ static int empty_dir(struct inode *inode)
1919 } 1919 }
1920 de = (struct ext4_dir_entry_2 *) bh->b_data; 1920 de = (struct ext4_dir_entry_2 *) bh->b_data;
1921 } 1921 }
1922 if (!ext4_check_dir_entry(inode, de, bh, offset)) { 1922 if (ext4_check_dir_entry(inode, de, bh, offset)) {
1923 de = (struct ext4_dir_entry_2 *)(bh->b_data + 1923 de = (struct ext4_dir_entry_2 *)(bh->b_data +
1924 sb->s_blocksize); 1924 sb->s_blocksize);
1925 offset = (offset | (sb->s_blocksize - 1)) + 1; 1925 offset = (offset | (sb->s_blocksize - 1)) + 1;