aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorTao Ma <boyu.mt@taobao.com>2012-12-10 14:05:58 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-12-10 14:05:58 -0500
commit226ba972b0863783ad377f741f6ff0538f31ab00 (patch)
tree72e089868a0856a1968d6118e359d0ae13f5cc91 /fs/ext4
parenta774f9c20e08643fc0e6c48b0419ad7657ed0c04 (diff)
ext4: refactor __ext4_check_dir_entry() to accept start and size
The __ext4_check_dir_entry() function() is used to check whether the de is over the block boundary. Now with inline data, it could be within the block boundary while exceeds the inode size. So check this function to check the overflow more precisely. Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/dir.c16
-rw-r--r--fs/ext4/ext4.h7
-rw-r--r--fs/ext4/namei.c13
3 files changed, 21 insertions, 15 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 8e07d2a5a139..7c9d08b0f2fe 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -72,7 +72,7 @@ static int is_dx_dir(struct inode *inode)
72int __ext4_check_dir_entry(const char *function, unsigned int line, 72int __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 cf840146ce81..59cbf498fd5f 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 *);
1960extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, 1960extern 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)))
1967extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, 1968extern 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 edb9f10c1455..10da2d50a5d8 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;