Skip to content

Commit

Permalink
udf: Fortify loading of sparing table
Browse files Browse the repository at this point in the history
Add sanity checks when loading sparing table from disk to avoid accessing
unallocated memory or writing to it.

Signed-off-by: Jan Kara <jack@suse.cz>
  • Loading branch information
jankara committed Jun 28, 2012
1 parent adee11b commit 1df2ae3
Showing 1 changed file with 53 additions and 33 deletions.
86 changes: 53 additions & 33 deletions fs/udf/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include <linux/seq_file.h>
#include <linux/bitmap.h>
#include <linux/crc-itu-t.h>
#include <linux/log2.h>
#include <asm/byteorder.h>

#include "udf_sb.h"
Expand Down Expand Up @@ -1215,11 +1216,59 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
return ret;
}

static int udf_load_sparable_map(struct super_block *sb,
struct udf_part_map *map,
struct sparablePartitionMap *spm)
{
uint32_t loc;
uint16_t ident;
struct sparingTable *st;
struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing;
int i;
struct buffer_head *bh;

map->s_partition_type = UDF_SPARABLE_MAP15;
sdata->s_packet_len = le16_to_cpu(spm->packetLength);
if (!is_power_of_2(sdata->s_packet_len)) {
udf_err(sb, "error loading logical volume descriptor: "
"Invalid packet length %u\n",
(unsigned)sdata->s_packet_len);
return -EIO;
}
if (spm->numSparingTables > 4) {
udf_err(sb, "error loading logical volume descriptor: "
"Too many sparing tables (%d)\n",
(int)spm->numSparingTables);
return -EIO;
}

for (i = 0; i < spm->numSparingTables; i++) {
loc = le32_to_cpu(spm->locSparingTable[i]);
bh = udf_read_tagged(sb, loc, loc, &ident);
if (!bh)
continue;

st = (struct sparingTable *)bh->b_data;
if (ident != 0 ||
strncmp(st->sparingIdent.ident, UDF_ID_SPARING,
strlen(UDF_ID_SPARING)) ||
sizeof(*st) + le16_to_cpu(st->reallocationTableLen) >
sb->s_blocksize) {
brelse(bh);
continue;
}

sdata->s_spar_map[i] = bh;
}
map->s_partition_func = udf_get_pblock_spar15;
return 0;
}

static int udf_load_logicalvol(struct super_block *sb, sector_t block,
struct kernel_lb_addr *fileset)
{
struct logicalVolDesc *lvd;
int i, j, offset;
int i, offset;
uint8_t type;
struct udf_sb_info *sbi = UDF_SB(sb);
struct genericPartitionMap *gpm;
Expand Down Expand Up @@ -1281,38 +1330,9 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
} else if (!strncmp(upm2->partIdent.ident,
UDF_ID_SPARABLE,
strlen(UDF_ID_SPARABLE))) {
uint32_t loc;
struct sparingTable *st;
struct sparablePartitionMap *spm =
(struct sparablePartitionMap *)gpm;

map->s_partition_type = UDF_SPARABLE_MAP15;
map->s_type_specific.s_sparing.s_packet_len =
le16_to_cpu(spm->packetLength);
for (j = 0; j < spm->numSparingTables; j++) {
struct buffer_head *bh2;

loc = le32_to_cpu(
spm->locSparingTable[j]);
bh2 = udf_read_tagged(sb, loc, loc,
&ident);
map->s_type_specific.s_sparing.
s_spar_map[j] = bh2;

if (bh2 == NULL)
continue;

st = (struct sparingTable *)bh2->b_data;
if (ident != 0 || strncmp(
st->sparingIdent.ident,
UDF_ID_SPARING,
strlen(UDF_ID_SPARING))) {
brelse(bh2);
map->s_type_specific.s_sparing.
s_spar_map[j] = NULL;
}
}
map->s_partition_func = udf_get_pblock_spar15;
if (udf_load_sparable_map(sb, map,
(struct sparablePartitionMap *)gpm) < 0)
goto out_bh;
} else if (!strncmp(upm2->partIdent.ident,
UDF_ID_METADATA,
strlen(UDF_ID_METADATA))) {
Expand Down

0 comments on commit 1df2ae3

Please sign in to comment.