aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf/super.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-06-27 15:23:07 -0400
committerJan Kara <jack@suse.cz>2012-06-28 13:31:09 -0400
commit1df2ae31c724e57be9d7ac00d78db8a5dabdd050 (patch)
tree359174ba11f0884c778c72c07578e5a35cf603e3 /fs/udf/super.c
parentadee11b2085bee90bd8f4f52123ffb07882d6256 (diff)
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>
Diffstat (limited to 'fs/udf/super.c')
-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 ce911f50b39d..8d86a8706c0e 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"
@@ -1215,11 +1216,59 @@ out_bh:
1215 return ret; 1216 return ret;
1216} 1217}
1217 1218
1219static 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
1218static int udf_load_logicalvol(struct super_block *sb, sector_t block, 1267static int udf_load_logicalvol(struct super_block *sb, sector_t block,
1219 struct kernel_lb_addr *fileset) 1268 struct kernel_lb_addr *fileset)
1220{ 1269{
1221 struct logicalVolDesc *lvd; 1270 struct logicalVolDesc *lvd;
1222 int i, j, offset; 1271 int i, offset;
1223 uint8_t type; 1272 uint8_t type;
1224 struct udf_sb_info *sbi = UDF_SB(sb); 1273 struct udf_sb_info *sbi = UDF_SB(sb);
1225 struct genericPartitionMap *gpm; 1274 struct genericPartitionMap *gpm;
@@ -1281,38 +1330,9 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
1281 } else if (!strncmp(upm2->partIdent.ident, 1330 } else if (!strncmp(upm2->partIdent.ident,
1282 UDF_ID_SPARABLE, 1331 UDF_ID_SPARABLE,
1283 strlen(UDF_ID_SPARABLE))) { 1332 strlen(UDF_ID_SPARABLE))) {
1284 uint32_t loc; 1333 if (udf_load_sparable_map(sb, map,
1285 struct sparingTable *st; 1334 (struct sparablePartitionMap *)gpm) < 0)
1286 struct sparablePartitionMap *spm = 1335 goto out_bh;
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;
1316 } else if (!strncmp(upm2->partIdent.ident, 1336 } else if (!strncmp(upm2->partIdent.ident,
1317 UDF_ID_METADATA, 1337 UDF_ID_METADATA,
1318 strlen(UDF_ID_METADATA))) { 1338 strlen(UDF_ID_METADATA))) {