Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F106071249
D33375.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D33375.diff
View Options
diff --git a/sys/fs/ext2fs/ext2_extents.c b/sys/fs/ext2fs/ext2_extents.c
--- a/sys/fs/ext2fs/ext2_extents.c
+++ b/sys/fs/ext2fs/ext2_extents.c
@@ -61,8 +61,10 @@
#ifdef EXT2FS_PRINT_EXTENTS
static const bool print_extents_walk = true;
-static int ext4_ext_check_header(struct inode *, struct ext4_extent_header *);
-static int ext4_ext_walk_header(struct inode *, struct ext4_extent_header *);
+static int ext4_ext_check_header(struct inode *, struct ext4_extent_header *,
+ int);
+static int ext4_ext_walk_header(struct inode *, struct ext4_extent_header *,
+ int);
static inline e4fs_daddr_t ext4_ext_index_pblock(struct ext4_extent_index *);
static inline e4fs_daddr_t ext4_ext_extent_pblock(struct ext4_extent *);
@@ -80,7 +82,8 @@
}
static int
-ext4_ext_walk_index(struct inode *ip, struct ext4_extent_index *ex, bool do_walk)
+ext4_ext_walk_index(struct inode *ip, struct ext4_extent_index *ex, int depth,
+ bool do_walk)
{
struct m_ext2fs *fs;
struct buf *bp;
@@ -91,7 +94,8 @@
if (print_extents_walk)
printf(" index %p => (blk %u pblk %ju)\n", ex,
- le32toh(ex->ei_blk), (uint64_t)le16toh(ex->ei_leaf_hi) << 32 |
+ le32toh(ex->ei_blk),
+ (uint64_t)le16toh(ex->ei_leaf_hi) << 32 |
le32toh(ex->ei_leaf_lo));
if(!do_walk)
@@ -108,7 +112,8 @@
return (error);
}
- error = ext4_ext_walk_header(ip, (struct ext4_extent_header *)bp->b_data);
+ error = ext4_ext_walk_header(ip,
+ (struct ext4_extent_header *)bp->b_data, depth);
brelse(bp);
@@ -135,42 +140,62 @@
}
static int
-ext4_ext_walk_header(struct inode *ip, struct ext4_extent_header *eh)
+ext4_ext_walk_header(struct inode *ip, struct ext4_extent_header *eh, int depth)
{
int i, error = 0;
- error = ext4_ext_check_header(ip, eh);
+ error = ext4_ext_check_header(ip, eh, depth);
if (error)
return (error);
if (print_extents_walk)
printf("header %p => (entries %d max %d depth %d gen %d)\n",
eh, le16toh(eh->eh_ecount),
- le16toh(eh->eh_max), le16toh(eh->eh_depth), le32toh(eh->eh_gen));
+ le16toh(eh->eh_max), le16toh(eh->eh_depth),
+ le32toh(eh->eh_gen));
for (i = 0; i < le16toh(eh->eh_ecount) && error == 0; i++)
if (eh->eh_depth != 0)
error = ext4_ext_walk_index(ip,
- (struct ext4_extent_index *)(eh + 1 + i), true);
+ (struct ext4_extent_index *)(eh + 1 + i), depth - 1,
+ true);
else
- error = ext4_ext_walk_extent(ip, (struct ext4_extent *)(eh + 1 + i));
+ error = ext4_ext_walk_extent(ip,
+ (struct ext4_extent *)(eh + 1 + i));
return (error);
}
+int
+ext4_ext_walk(struct inode *ip)
+{
+ struct ext4_extent_header *ehp;
+
+ ehp = (struct ext4_extent_header *)ip->i_db;
+
+ if (print_extents_walk)
+ printf("Extent status:ip=%ju\n", ip->i_number);
+
+ if (!(ip->i_flag & IN_E4EXTENTS))
+ return (0);
+
+ return (ext4_ext_walk_header(ip, ehp, 0));
+}
+
static int
ext4_ext_print_path(struct inode *ip, struct ext4_extent_path *path)
{
- int k, l, error = 0;
+ int k, depth, error = 0;
- l = path->ep_depth;
+ depth = path->ep_depth;
if (print_extents_walk)
printf("ip=%ju, Path:\n", ip->i_number);
- for (k = 0; k <= l && error == 0; k++, path++) {
+ for (k = 0; k <= depth && error == 0; k++, path++) {
if (path->ep_index) {
- error = ext4_ext_walk_index(ip, path->ep_index, false);
+ error = ext4_ext_walk_index(ip, path->ep_index,
+ depth - 1, false);
} else if (path->ep_ext) {
error = ext4_ext_walk_extent(ip, path->ep_ext);
}
@@ -178,22 +203,6 @@
return (error);
}
-
-int
-ext4_ext_walk(struct inode *ip)
-{
- struct ext4_extent_header *ehp;
-
- ehp = (struct ext4_extent_header *)ip->i_db;
-
- if (print_extents_walk)
- printf("Extent status:ip=%ju\n", ip->i_number);
-
- if (!(ip->i_flag & IN_E4EXTENTS))
- return (0);
-
- return (ext4_ext_walk_header(ip, ehp));
-}
#endif
static inline struct ext4_extent_header *
@@ -277,8 +286,168 @@
return (ret);
}
+static inline int
+ext4_ext_space_root(struct inode *ip)
+{
+ int size;
+
+ size = sizeof(ip->i_data);
+ size -= sizeof(struct ext4_extent_header);
+ size /= sizeof(struct ext4_extent);
+
+ return (size);
+}
+
+static inline int
+ext4_ext_space_block(struct inode *ip)
+{
+ struct m_ext2fs *fs;
+ int size;
+
+ fs = ip->i_e2fs;
+
+ size = (fs->e2fs_bsize - sizeof(struct ext4_extent_header)) /
+ sizeof(struct ext4_extent);
+
+ return (size);
+}
+
+static inline int
+ext4_ext_space_root_idx(struct inode *ip)
+{
+ int size;
+
+ size = sizeof(ip->i_data);
+ size -= sizeof(struct ext4_extent_header);
+ size /= sizeof(struct ext4_extent_index);
+
+ return (size);
+}
+
+static inline int
+ext4_ext_space_block_idx(struct inode *ip)
+{
+ struct m_ext2fs *fs;
+ int size;
+
+ fs = ip->i_e2fs;
+
+ size = (fs->e2fs_bsize - sizeof(struct ext4_extent_header)) /
+ sizeof(struct ext4_extent_index);
+
+ return (size);
+}
+
static int
-ext4_ext_check_header(struct inode *ip, struct ext4_extent_header *eh)
+ext4_ext_max_entries(struct inode *ip, int depth)
+{
+
+ if (depth == ext4_ext_inode_depth(ip)) {
+ if (depth == 0)
+ return (ext4_ext_space_root(ip));
+ else
+ return (ext4_ext_space_root_idx(ip));
+ } else {
+ if (depth == 0)
+ return (ext4_ext_space_block(ip));
+ else
+ return (ext4_ext_space_block_idx(ip));
+ }
+}
+
+static inline uint16_t
+ext4_ext_get_actual_len(struct ext4_extent *ext)
+{
+
+ return (le16toh(ext->e_len) <= EXT_INIT_MAX_LEN ?
+ le16toh(ext->e_len) : (le16toh(ext->e_len) - EXT_INIT_MAX_LEN));
+}
+
+
+static int
+ext4_inode_block_validate(struct inode *ip, e4fs_daddr_t start_blk,
+ unsigned int count)
+{
+ struct m_ext2fs *fs;
+
+ fs = ip->i_e2fs;
+
+ if ((start_blk <= le32toh(fs->e2fs->e2fs_first_dblock)) ||
+ (start_blk + count < start_blk) ||
+ (start_blk + count > fs->e2fs_bcount))
+ return (EIO);
+
+ return (0);
+}
+
+static int
+ext4_validate_extent(struct inode *ip, struct ext4_extent *ext)
+{
+ e4fs_daddr_t blk = ext4_ext_extent_pblock(ext);
+ uint32_t lblk = le32toh(ext->e_blk);
+ int len = ext4_ext_get_actual_len(ext);
+
+ if (lblk + len <= lblk)
+ return (EIO);
+
+ return (ext4_inode_block_validate(ip, blk, len));
+}
+
+static int
+ext4_validate_extent_idx(struct inode *ip, struct ext4_extent_index *ext_idx)
+{
+ e4fs_daddr_t blk = ext4_ext_index_pblock(ext_idx);
+
+ return (ext4_inode_block_validate(ip, blk, 1));
+}
+
+static int
+ext4_validate_extent_entries(struct inode *ip, struct ext4_extent_header *eh,
+ int depth)
+{
+ unsigned int count;
+
+ count = le16toh(eh->eh_ecount);
+ if (count == 0)
+ return (0);
+
+ if (depth == 0) {
+ struct ext4_extent *ext = EXT_FIRST_EXTENT(eh);
+ uint32_t lblk = 0;
+ uint32_t prev = 0;
+ int len = 0;
+ while (count) {
+ /* leaf entries */
+ if (ext4_validate_extent(ip, ext))
+ return (EIO);
+
+ /* Check for overlapping extents */
+ lblk = le32toh(ext->e_blk);
+ len = ext4_ext_get_actual_len(ext);
+ if ((lblk <= prev) && prev)
+ return (EIO);
+
+ ext++;
+ count--;
+ prev = lblk + len - 1;
+ }
+ } else {
+ struct ext4_extent_index *ext_idx = EXT_FIRST_INDEX(eh);
+ while (count) {
+ if (ext4_validate_extent_idx(ip, ext_idx))
+ return (EIO);
+
+ ext_idx++;
+ count--;
+ }
+ }
+
+ return (0);
+}
+
+static int
+ext4_ext_check_header(struct inode *ip, struct ext4_extent_header *eh,
+ int depth)
{
char *error_msg;
@@ -286,18 +455,32 @@
error_msg = "header: invalid magic";
goto corrupted;
}
+ if (le16toh(eh->eh_depth) != depth ||
+ le16toh(eh->eh_depth) > EXT4_EXT_DEPTH_MAX)
+ {
+ error_msg = "header: invalid eh_depth";
+ goto corrupted;
+ }
if (eh->eh_max == 0) {
error_msg = "header: invalid eh_max";
goto corrupted;
}
+ if (le16toh(eh->eh_max) > ext4_ext_max_entries(ip, depth)) {
+ error_msg = "header: too large eh_max";
+ goto corrupted;
+ }
if (le16toh(eh->eh_ecount) > le16toh(eh->eh_max)) {
error_msg = "header: invalid eh_entries";
goto corrupted;
}
- if (eh->eh_depth > 5) {
+ if (le16toh(eh->eh_depth) > EXT4_EXT_DEPTH_MAX) {
error_msg = "header: invalid eh_depth";
goto corrupted;
}
+ if (ext4_validate_extent_entries(ip, eh, depth)) {
+ error_msg = "header: invalid extent entries";
+ goto corrupted;
+ }
return (0);
@@ -426,7 +609,7 @@
ppos = 0;
alloc = 0;
- error = ext4_ext_check_header(ip, eh);
+ error = ext4_ext_check_header(ip, eh, depth);
if (error)
return (error);
@@ -472,7 +655,7 @@
bqrelse(bp);
eh = ext4_ext_block_header(path[ppos].ep_data);
- if (ext4_ext_check_header(ip, eh) ||
+ if (ext4_ext_check_header(ip, eh, i - 1) ||
ext2_extent_blk_csum_verify(ip, path[ppos].ep_data)) {
error = EIO;
goto error;
@@ -483,7 +666,7 @@
i--;
}
- error = ext4_ext_check_header(ip, eh);
+ error = ext4_ext_check_header(ip, eh, 0);
if (error)
goto error;
@@ -505,32 +688,6 @@
return (error);
}
-static inline int
-ext4_ext_space_root(struct inode *ip)
-{
- int size;
-
- size = sizeof(ip->i_data);
- size -= sizeof(struct ext4_extent_header);
- size /= sizeof(struct ext4_extent);
-
- return (size);
-}
-
-static inline int
-ext4_ext_space_block(struct inode *ip)
-{
- struct m_ext2fs *fs;
- int size;
-
- fs = ip->i_e2fs;
-
- size = (fs->e2fs_bsize - sizeof(struct ext4_extent_header)) /
- sizeof(struct ext4_extent);
-
- return (size);
-}
-
static inline int
ext4_ext_space_block_index(struct inode *ip)
{
@@ -1339,14 +1496,6 @@
return (error);
}
-static inline uint16_t
-ext4_ext_get_actual_len(struct ext4_extent *ext)
-{
-
- return (le16toh(ext->e_len) <= EXT_INIT_MAX_LEN ?
- le16toh(ext->e_len) : (le16toh(ext->e_len) - EXT_INIT_MAX_LEN));
-}
-
static inline struct ext4_extent_header *
ext4_ext_header(struct inode *ip)
{
@@ -1503,7 +1652,7 @@
goto err;
}
- error = ext4_ext_check_header(ip, eh);
+ error = ext4_ext_check_header(ip, eh, depth);
if (error)
goto err;
@@ -1544,7 +1693,7 @@
ehp = (struct ext4_extent_header *)ip->i_db;
depth = ext4_ext_inode_depth(ip);
- error = ext4_ext_check_header(ip, ehp);
+ error = ext4_ext_check_header(ip, ehp, depth);
if(error)
return (error);
diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c
--- a/sys/fs/ext2fs/ext2_inode_cnv.c
+++ b/sys/fs/ext2fs/ext2_inode_cnv.c
@@ -65,11 +65,11 @@
in->i_uid, in->i_gid, (uintmax_t)in->i_size);
printf("Links: %3d Blockcount: %ju\n",
in->i_nlink, (uintmax_t)in->i_blocks);
- printf("ctime: 0x%x ", in->i_ctime);
- printf("atime: 0x%x ", in->i_atime);
- printf("mtime: 0x%x ", in->i_mtime);
+ printf("ctime: 0x%llx ", (unsigned long long)in->i_ctime);
+ printf("atime: 0x%llx ", (unsigned long long)in->i_atime);
+ printf("mtime: 0x%llx ", (unsigned long long)in->i_mtime);
if (E2DI_HAS_XTIME(in))
- printf("crtime %#x\n", in->i_birthtime);
+ printf("crtime %llx\n", (unsigned long long)in->i_birthtime);
else
printf("\n");
if (in->i_flag & IN_E4EXTENTS) {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Dec 25, 10:06 PM (11 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15598937
Default Alt Text
D33375.diff (10 KB)
Attached To
Mode
D33375: Improve extents verification logic
Attached
Detach File
Event Timeline
Log In to Comment