diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/dir.c | 16 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 7 | ||||
-rw-r--r-- | fs/ext4/namei.c | 13 |
3 files changed, 21 insertions, 15 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 8e07d2a5a13..7c9d08b0f2f 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c | |||
@@ -72,7 +72,7 @@ static int is_dx_dir(struct inode *inode) | |||
72 | int __ext4_check_dir_entry(const char *function, unsigned int line, | 72 | int __ext4_check_dir_entry(const char *function, unsigned int line, |
73 | struct inode *dir, struct file *filp, | 73 | struct inode *dir, struct file *filp, |
74 | struct ext4_dir_entry_2 *de, | 74 | struct ext4_dir_entry_2 *de, |
75 | struct buffer_head *bh, | 75 | struct buffer_head *bh, char *buf, int size, |
76 | unsigned int offset) | 76 | unsigned int offset) |
77 | { | 77 | { |
78 | const char *error_msg = NULL; | 78 | const char *error_msg = NULL; |
@@ -85,9 +85,8 @@ int __ext4_check_dir_entry(const char *function, unsigned int line, | |||
85 | error_msg = "rec_len % 4 != 0"; | 85 | error_msg = "rec_len % 4 != 0"; |
86 | else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len))) | 86 | else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len))) |
87 | error_msg = "rec_len is too small for name_len"; | 87 | error_msg = "rec_len is too small for name_len"; |
88 | else if (unlikely(((char *) de - bh->b_data) + rlen > | 88 | else if (unlikely(((char *) de - buf) + rlen > size)) |
89 | dir->i_sb->s_blocksize)) | 89 | error_msg = "directory entry across range"; |
90 | error_msg = "directory entry across blocks"; | ||
91 | else if (unlikely(le32_to_cpu(de->inode) > | 90 | else if (unlikely(le32_to_cpu(de->inode) > |
92 | le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))) | 91 | le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))) |
93 | error_msg = "inode out of bounds"; | 92 | error_msg = "inode out of bounds"; |
@@ -98,14 +97,14 @@ int __ext4_check_dir_entry(const char *function, unsigned int line, | |||
98 | ext4_error_file(filp, function, line, bh->b_blocknr, | 97 | ext4_error_file(filp, function, line, bh->b_blocknr, |
99 | "bad entry in directory: %s - offset=%u(%u), " | 98 | "bad entry in directory: %s - offset=%u(%u), " |
100 | "inode=%u, rec_len=%d, name_len=%d", | 99 | "inode=%u, rec_len=%d, name_len=%d", |
101 | error_msg, (unsigned) (offset % bh->b_size), | 100 | error_msg, (unsigned) (offset % size), |
102 | offset, le32_to_cpu(de->inode), | 101 | offset, le32_to_cpu(de->inode), |
103 | rlen, de->name_len); | 102 | rlen, de->name_len); |
104 | else | 103 | else |
105 | ext4_error_inode(dir, function, line, bh->b_blocknr, | 104 | ext4_error_inode(dir, function, line, bh->b_blocknr, |
106 | "bad entry in directory: %s - offset=%u(%u), " | 105 | "bad entry in directory: %s - offset=%u(%u), " |
107 | "inode=%u, rec_len=%d, name_len=%d", | 106 | "inode=%u, rec_len=%d, name_len=%d", |
108 | error_msg, (unsigned) (offset % bh->b_size), | 107 | error_msg, (unsigned) (offset % size), |
109 | offset, le32_to_cpu(de->inode), | 108 | offset, le32_to_cpu(de->inode), |
110 | rlen, de->name_len); | 109 | rlen, de->name_len); |
111 | 110 | ||
@@ -221,8 +220,9 @@ revalidate: | |||
221 | while (!error && filp->f_pos < inode->i_size | 220 | while (!error && filp->f_pos < inode->i_size |
222 | && offset < sb->s_blocksize) { | 221 | && offset < sb->s_blocksize) { |
223 | de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); | 222 | de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); |
224 | if (ext4_check_dir_entry(inode, filp, de, | 223 | if (ext4_check_dir_entry(inode, filp, de, bh, |
225 | bh, offset)) { | 224 | bh->b_data, bh->b_size, |
225 | offset)) { | ||
226 | /* | 226 | /* |
227 | * On error, skip the f_pos to the next block | 227 | * On error, skip the f_pos to the next block |
228 | */ | 228 | */ |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index cf840146ce8..59cbf498fd5 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1960,10 +1960,11 @@ ext4_fsblk_t ext4_inode_to_goal_block(struct inode *); | |||
1960 | extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, | 1960 | extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, |
1961 | struct file *, | 1961 | struct file *, |
1962 | struct ext4_dir_entry_2 *, | 1962 | struct ext4_dir_entry_2 *, |
1963 | struct buffer_head *, unsigned int); | 1963 | struct buffer_head *, char *, int, |
1964 | #define ext4_check_dir_entry(dir, filp, de, bh, offset) \ | 1964 | unsigned int); |
1965 | #define ext4_check_dir_entry(dir, filp, de, bh, buf, size, offset) \ | ||
1965 | unlikely(__ext4_check_dir_entry(__func__, __LINE__, (dir), (filp), \ | 1966 | unlikely(__ext4_check_dir_entry(__func__, __LINE__, (dir), (filp), \ |
1966 | (de), (bh), (offset))) | 1967 | (de), (bh), (buf), (size), (offset))) |
1967 | extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, | 1968 | extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, |
1968 | __u32 minor_hash, | 1969 | __u32 minor_hash, |
1969 | struct ext4_dir_entry_2 *dirent); | 1970 | struct ext4_dir_entry_2 *dirent); |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index edb9f10c145..10da2d50a5d 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -892,6 +892,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
892 | EXT4_DIR_REC_LEN(0)); | 892 | EXT4_DIR_REC_LEN(0)); |
893 | for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { | 893 | for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { |
894 | if (ext4_check_dir_entry(dir, NULL, de, bh, | 894 | if (ext4_check_dir_entry(dir, NULL, de, bh, |
895 | bh->b_data, bh->b_size, | ||
895 | (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb)) | 896 | (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb)) |
896 | + ((char *)de - bh->b_data))) { | 897 | + ((char *)de - bh->b_data))) { |
897 | /* On error, skip the f_pos to the next block. */ | 898 | /* On error, skip the f_pos to the next block. */ |
@@ -1130,7 +1131,8 @@ static inline int search_dirblock(struct buffer_head *bh, | |||
1130 | if ((char *) de + namelen <= dlimit && | 1131 | if ((char *) de + namelen <= dlimit && |
1131 | ext4_match (namelen, name, de)) { | 1132 | ext4_match (namelen, name, de)) { |
1132 | /* found a match - just to be sure, do a full check */ | 1133 | /* found a match - just to be sure, do a full check */ |
1133 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) | 1134 | if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, |
1135 | bh->b_size, offset)) | ||
1134 | return -1; | 1136 | return -1; |
1135 | *res_dir = de; | 1137 | *res_dir = de; |
1136 | return 1; | 1138 | return 1; |
@@ -1643,7 +1645,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1643 | de = (struct ext4_dir_entry_2 *)bh->b_data; | 1645 | de = (struct ext4_dir_entry_2 *)bh->b_data; |
1644 | top = bh->b_data + (blocksize - csum_size) - reclen; | 1646 | top = bh->b_data + (blocksize - csum_size) - reclen; |
1645 | while ((char *) de <= top) { | 1647 | while ((char *) de <= top) { |
1646 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) | 1648 | if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, |
1649 | bh->b_size, offset)) | ||
1647 | return -EIO; | 1650 | return -EIO; |
1648 | if (ext4_match(namelen, name, de)) | 1651 | if (ext4_match(namelen, name, de)) |
1649 | return -EEXIST; | 1652 | return -EEXIST; |
@@ -2076,7 +2079,8 @@ static int ext4_delete_entry(handle_t *handle, | |||
2076 | pde = NULL; | 2079 | pde = NULL; |
2077 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2080 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
2078 | while (i < bh->b_size - csum_size) { | 2081 | while (i < bh->b_size - csum_size) { |
2079 | if (ext4_check_dir_entry(dir, NULL, de, bh, i)) | 2082 | if (ext4_check_dir_entry(dir, NULL, de, bh, |
2083 | bh->b_data, bh->b_size, i)) | ||
2080 | return -EIO; | 2084 | return -EIO; |
2081 | if (de == de_del) { | 2085 | if (de == de_del) { |
2082 | BUFFER_TRACE(bh, "get_write_access"); | 2086 | BUFFER_TRACE(bh, "get_write_access"); |
@@ -2439,7 +2443,8 @@ static int empty_dir(struct inode *inode) | |||
2439 | set_buffer_verified(bh); | 2443 | set_buffer_verified(bh); |
2440 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2444 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
2441 | } | 2445 | } |
2442 | if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) { | 2446 | if (ext4_check_dir_entry(inode, NULL, de, bh, |
2447 | bh->b_data, bh->b_size, offset)) { | ||
2443 | de = (struct ext4_dir_entry_2 *)(bh->b_data + | 2448 | de = (struct ext4_dir_entry_2 *)(bh->b_data + |
2444 | sb->s_blocksize); | 2449 | sb->s_blocksize); |
2445 | offset = (offset | (sb->s_blocksize - 1)) + 1; | 2450 | offset = (offset | (sb->s_blocksize - 1)) + 1; |