mirror of https://gitee.com/openkylin/linux.git
udf: Fortify loading of sparing table
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>
This commit is contained in:
parent
adee11b208
commit
1df2ae31c7
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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))) {
|
||||
|
|
Loading…
Reference in New Issue