summaryrefslogtreecommitdiff
path: root/fs/udf/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/udf/super.c')
-rw-r--r--fs/udf/super.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 9381a66c6ce5..b2f168b0a0d1 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -336,7 +336,8 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
int nr_groups = bitmap->s_nr_groups;
for (i = 0; i < nr_groups; i++)
- brelse(bitmap->s_block_bitmap[i]);
+ if (!IS_ERR_OR_NULL(bitmap->s_block_bitmap[i]))
+ brelse(bitmap->s_block_bitmap[i]);
kvfree(bitmap);
}
@@ -1110,12 +1111,19 @@ static int udf_fill_partdesc_info(struct super_block *sb,
struct udf_part_map *map;
struct udf_sb_info *sbi = UDF_SB(sb);
struct partitionHeaderDesc *phd;
+ u32 sum;
int err;
map = &sbi->s_partmaps[p_index];
map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */
map->s_partition_root = le32_to_cpu(p->partitionStartingLocation);
+ if (check_add_overflow(map->s_partition_root, map->s_partition_len,
+ &sum)) {
+ udf_err(sb, "Partition %d has invalid location %u + %u\n",
+ p_index, map->s_partition_root, map->s_partition_len);
+ return -EFSCORRUPTED;
+ }
if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY))
map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY;
@@ -1171,6 +1179,14 @@ static int udf_fill_partdesc_info(struct super_block *sb,
bitmap->s_extPosition = le32_to_cpu(
phd->unallocSpaceBitmap.extPosition);
map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP;
+ /* Check whether math over bitmap won't overflow. */
+ if (check_add_overflow(map->s_partition_len,
+ sizeof(struct spaceBitmapDesc) << 3,
+ &sum)) {
+ udf_err(sb, "Partition %d is too long (%u)\n", p_index,
+ map->s_partition_len);
+ return -EFSCORRUPTED;
+ }
udf_debug("unallocSpaceBitmap (part %d) @ %u\n",
p_index, bitmap->s_extPosition);
}
@@ -1424,7 +1440,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
struct genericPartitionMap *gpm;
uint16_t ident;
struct buffer_head *bh;
- unsigned int table_len;
+ unsigned int table_len, part_map_count;
int ret;
bh = udf_read_tagged(sb, block, block, &ident);
@@ -1445,7 +1461,16 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
"logical volume");
if (ret)
goto out_bh;
- ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps));
+
+ part_map_count = le32_to_cpu(lvd->numPartitionMaps);
+ if (part_map_count > table_len / sizeof(struct genericPartitionMap1)) {
+ udf_err(sb, "error loading logical volume descriptor: "
+ "Too many partition maps (%u > %u)\n", part_map_count,
+ table_len / (unsigned)sizeof(struct genericPartitionMap1));
+ ret = -EIO;
+ goto out_bh;
+ }
+ ret = udf_sb_alloc_partition_maps(sb, part_map_count);
if (ret)
goto out_bh;
@@ -2466,13 +2491,14 @@ static unsigned int udf_count_free_table(struct super_block *sb,
uint32_t elen;
struct kernel_lb_addr eloc;
struct extent_position epos;
+ int8_t etype;
mutex_lock(&UDF_SB(sb)->s_alloc_mutex);
epos.block = UDF_I(table)->i_location;
epos.offset = sizeof(struct unallocSpaceEntry);
epos.bh = NULL;
- while (udf_next_aext(table, &epos, &eloc, &elen, 1) != -1)
+ while (udf_next_aext(table, &epos, &eloc, &elen, &etype, 1) > 0)
accum += (elen >> table->i_sb->s_blocksize_bits);
brelse(epos.bh);