Skip to content

Commit 1df2ae3

Browse files
committed
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>
1 parent adee11b commit 1df2ae3

1 file changed

Lines changed: 53 additions & 33 deletions

File tree

fs/udf/super.c

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include <linux/seq_file.h>
5757
#include <linux/bitmap.h>
5858
#include <linux/crc-itu-t.h>
59+
#include <linux/log2.h>
5960
#include <asm/byteorder.h>
6061

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

1219+
static int udf_load_sparable_map(struct super_block *sb,
1220+
struct udf_part_map *map,
1221+
struct sparablePartitionMap *spm)
1222+
{
1223+
uint32_t loc;
1224+
uint16_t ident;
1225+
struct sparingTable *st;
1226+
struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing;
1227+
int i;
1228+
struct buffer_head *bh;
1229+
1230+
map->s_partition_type = UDF_SPARABLE_MAP15;
1231+
sdata->s_packet_len = le16_to_cpu(spm->packetLength);
1232+
if (!is_power_of_2(sdata->s_packet_len)) {
1233+
udf_err(sb, "error loading logical volume descriptor: "
1234+
"Invalid packet length %u\n",
1235+
(unsigned)sdata->s_packet_len);
1236+
return -EIO;
1237+
}
1238+
if (spm->numSparingTables > 4) {
1239+
udf_err(sb, "error loading logical volume descriptor: "
1240+
"Too many sparing tables (%d)\n",
1241+
(int)spm->numSparingTables);
1242+
return -EIO;
1243+
}
1244+
1245+
for (i = 0; i < spm->numSparingTables; i++) {
1246+
loc = le32_to_cpu(spm->locSparingTable[i]);
1247+
bh = udf_read_tagged(sb, loc, loc, &ident);
1248+
if (!bh)
1249+
continue;
1250+
1251+
st = (struct sparingTable *)bh->b_data;
1252+
if (ident != 0 ||
1253+
strncmp(st->sparingIdent.ident, UDF_ID_SPARING,
1254+
strlen(UDF_ID_SPARING)) ||
1255+
sizeof(*st) + le16_to_cpu(st->reallocationTableLen) >
1256+
sb->s_blocksize) {
1257+
brelse(bh);
1258+
continue;
1259+
}
1260+
1261+
sdata->s_spar_map[i] = bh;
1262+
}
1263+
map->s_partition_func = udf_get_pblock_spar15;
1264+
return 0;
1265+
}
1266+
12181267
static int udf_load_logicalvol(struct super_block *sb, sector_t block,
12191268
struct kernel_lb_addr *fileset)
12201269
{
12211270
struct logicalVolDesc *lvd;
1222-
int i, j, offset;
1271+
int i, offset;
12231272
uint8_t type;
12241273
struct udf_sb_info *sbi = UDF_SB(sb);
12251274
struct genericPartitionMap *gpm;
@@ -1281,38 +1330,9 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
12811330
} else if (!strncmp(upm2->partIdent.ident,
12821331
UDF_ID_SPARABLE,
12831332
strlen(UDF_ID_SPARABLE))) {
1284-
uint32_t loc;
1285-
struct sparingTable *st;
1286-
struct sparablePartitionMap *spm =
1287-
(struct sparablePartitionMap *)gpm;
1288-
1289-
map->s_partition_type = UDF_SPARABLE_MAP15;
1290-
map->s_type_specific.s_sparing.s_packet_len =
1291-
le16_to_cpu(spm->packetLength);
1292-
for (j = 0; j < spm->numSparingTables; j++) {
1293-
struct buffer_head *bh2;
1294-
1295-
loc = le32_to_cpu(
1296-
spm->locSparingTable[j]);
1297-
bh2 = udf_read_tagged(sb, loc, loc,
1298-
&ident);
1299-
map->s_type_specific.s_sparing.
1300-
s_spar_map[j] = bh2;
1301-
1302-
if (bh2 == NULL)
1303-
continue;
1304-
1305-
st = (struct sparingTable *)bh2->b_data;
1306-
if (ident != 0 || strncmp(
1307-
st->sparingIdent.ident,
1308-
UDF_ID_SPARING,
1309-
strlen(UDF_ID_SPARING))) {
1310-
brelse(bh2);
1311-
map->s_type_specific.s_sparing.
1312-
s_spar_map[j] = NULL;
1313-
}
1314-
}
1315-
map->s_partition_func = udf_get_pblock_spar15;
1333+
if (udf_load_sparable_map(sb, map,
1334+
(struct sparablePartitionMap *)gpm) < 0)
1335+
goto out_bh;
13161336
} else if (!strncmp(upm2->partIdent.ident,
13171337
UDF_ID_METADATA,
13181338
strlen(UDF_ID_METADATA))) {

0 commit comments

Comments
 (0)