aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-06-27 15:23:07 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 11:47:38 -0400
commitb1c5701ad6b3e5d21d16f65475651cfaaa41e7aa (patch)
tree3ac3a4068453e113f335bc339c36b1a46b017e03
parent8411aa07c7aa22ef3fe269a05e45e672590e4f7f (diff)
udf: Fortify loading of sparing table
commit 1df2ae31c724e57be9d7ac00d78db8a5dabdd050 upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/udf/super.c86
1 files changed, 53 insertions, 33 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c
index ee31a2ad087..a8e867ae11c 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -56,6 +56,7 @@
56#include <linux/seq_file.h> 56#include <linux/seq_file.h>
57#include <linux/bitmap.h> 57#include <linux/bitmap.h>
58#include <linux/crc-itu-t.h> 58#include <linux/crc-itu-t.h>
59#include <linux/log2.h>
59#include <asm/byteorder.h> 60#include <asm/byteorder.h>
60 61
61#include "udf_sb.h" 62#include "udf_sb.h"
@@ -1244,11 +1245,59 @@ out_bh:
1244 return ret; 1245 return ret;
1245} 1246}
1246 1247
1248static int udf_load_sparable_map(struct super_block *sb,
1249 struct udf_part_map *map,
1250 struct sparablePartitionMap *spm)
1251{
1252 uint32_t loc;
1253 uint16_t ident;
1254 struct sparingTable *st;
1255 struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing;
1256 int i;
1257 struct buffer_head *bh;
1258
1259 map->s_partition_type = UDF_SPARABLE_MAP15;
1260 sdata->s_packet_len = le16_to_cpu(spm->packetLength);
1261 if (!is_power_of_2(sdata->s_packet_len)) {
1262 udf_error(sb, __func__, "error loading logical volume descriptor: "
1263 "Invalid packet length %u\n",
1264 (unsigned)sdata->s_packet_len);
1265 return -EIO;
1266 }
1267 if (spm->numSparingTables > 4) {
1268 udf_error(sb, __func__, "error loading logical volume descriptor: "
1269 "Too many sparing tables (%d)\n",
1270 (int)spm->numSparingTables);
1271 return -EIO;
1272 }
1273
1274 for (i = 0; i < spm->numSparingTables; i++) {
1275 loc = le32_to_cpu(spm->locSparingTable[i]);
1276 bh = udf_read_tagged(sb, loc, loc, &ident);
1277 if (!bh)
1278 continue;
1279
1280 st = (struct sparingTable *)bh->b_data;
1281 if (ident != 0 ||
1282 strncmp(st->sparingIdent.ident, UDF_ID_SPARING,
1283 strlen(UDF_ID_SPARING)) ||
1284 sizeof(*st) + le16_to_cpu(st->reallocationTableLen) >
1285 sb->s_blocksize) {
1286 brelse(bh);
1287 continue;
1288 }
1289
1290 sdata->s_spar_map[i] = bh;
1291 }
1292 map->s_partition_func = udf_get_pblock_spar15;
1293 return 0;
1294}
1295
1247static int udf_load_logicalvol(struct super_block *sb, sector_t block, 1296static int udf_load_logicalvol(struct super_block *sb, sector_t block,
1248 struct kernel_lb_addr *fileset) 1297 struct kernel_lb_addr *fileset)
1249{ 1298{
1250 struct logicalVolDesc *lvd; 1299 struct logicalVolDesc *lvd;
1251 int i, j, offset; 1300 int i, offset;
1252 uint8_t type; 1301 uint8_t type;
1253 struct udf_sb_info *sbi = UDF_SB(sb); 1302 struct udf_sb_info *sbi = UDF_SB(sb);
1254 struct genericPartitionMap *gpm; 1303 struct genericPartitionMap *gpm;
@@ -1310,38 +1359,9 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
1310 } else if (!strncmp(upm2->partIdent.ident, 1359 } else if (!strncmp(upm2->partIdent.ident,
1311 UDF_ID_SPARABLE, 1360 UDF_ID_SPARABLE,
1312 strlen(UDF_ID_SPARABLE))) { 1361 strlen(UDF_ID_SPARABLE))) {
1313 uint32_t loc; 1362 if (udf_load_sparable_map(sb, map,
1314 struct sparingTable *st; 1363 (struct sparablePartitionMap *)gpm) < 0)
1315 struct sparablePartitionMap *spm = 1364 goto out_bh;
1316 (struct sparablePartitionMap *)gpm;
1317
1318 map->s_partition_type = UDF_SPARABLE_MAP15;
1319 map->s_type_specific.s_sparing.s_packet_len =
1320 le16_to_cpu(spm->packetLength);
1321 for (j = 0; j < spm->numSparingTables; j++) {
1322 struct buffer_head *bh2;
1323
1324 loc = le32_to_cpu(
1325 spm->locSparingTable[j]);
1326 bh2 = udf_read_tagged(sb, loc, loc,
1327 &ident);
1328 map->s_type_specific.s_sparing.
1329 s_spar_map[j] = bh2;
1330
1331 if (bh2 == NULL)
1332 continue;
1333
1334 st = (struct sparingTable *)bh2->b_data;
1335 if (ident != 0 || strncmp(
1336 st->sparingIdent.ident,
1337 UDF_ID_SPARING,
1338 strlen(UDF_ID_SPARING))) {
1339 brelse(bh2);
1340 map->s_type_specific.s_sparing.
1341 s_spar_map[j] = NULL;
1342 }
1343 }
1344 map->s_partition_func = udf_get_pblock_spar15;
1345 } else if (!strncmp(upm2->partIdent.ident, 1365 } else if (!strncmp(upm2->partIdent.ident,
1346 UDF_ID_METADATA, 1366 UDF_ID_METADATA,
1347 strlen(UDF_ID_METADATA))) { 1367 strlen(UDF_ID_METADATA))) {