diff --git a/fs/hfs/btree.h b/fs/hfs/btree.h index b4c3f2a31471..1f703f2c53d8 100644 --- a/fs/hfs/btree.h +++ b/fs/hfs/btree.h @@ -84,6 +84,25 @@ struct hfs_find_data { int entryoffset, entrylength; }; +static inline bool is_hfs_bnode_range_valid(struct hfs_find_data *fd, + size_t expected_len) +{ + struct hfs_bnode *node; + + if (!fd) + return false; + + node = fd->bnode; + if (!node || !node->tree) + return false; + + if (fd->entryoffset < 0 || fd->entrylength != expected_len) + return false; + + return (u64)fd->entryoffset + fd->entrylength <= + node->tree->node_size; +} + /* btree.c */ extern struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index f066a99a863b..26357086517f 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -121,12 +121,18 @@ static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) res = hfs_bmap_reserve(fd->tree, fd->tree->depth + 1); if (res) return res; - hfs_brec_insert(fd, HFS_I(inode)->cached_extents, sizeof(hfs_extent_rec)); + res = hfs_brec_insert(fd, HFS_I(inode)->cached_extents, + sizeof(hfs_extent_rec)); + if (res) + return res; HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); } else { if (res) return res; - hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, fd->entryoffset, fd->entrylength); + if (!is_hfs_bnode_range_valid(fd, sizeof(hfs_extent_rec))) + return -ERANGE; + hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, + fd->entryoffset, fd->entrylength); HFS_I(inode)->flags &= ~HFS_FLG_EXT_DIRTY; } return 0;