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 @@ out_bh: | ||||
| 	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
	
	Block a user