Changeset - r18048:2425acc9f405
[Not reviewed]
master
0 3 0
michi_cc - 13 years ago 2011-09-02 20:16:34
michi_cc@openttd.org
(svn r22873) -Fix [FS#4747]: Validate image dimensions before loading. (Based on patch by monoid)
3 files changed with 35 insertions and 3 deletions:
0 comments (0 inline, 0 general)
src/heightmap.cpp
Show inline comments
 
@@ -133,31 +133,42 @@ static bool ReadHeightmapPNG(char *filen
 
	png_set_packing(png_ptr);
 
	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, NULL);
 

	
 
	/* Maps of wrong colour-depth are not used.
 
	 * (this should have been taken care of by stripping alpha and 16-bit samples on load) */
 
	if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) {
 
		ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR);
 
		fclose(fp);
 
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
		return false;
 
	}
 

	
 
	uint width = png_get_image_width(png_ptr, info_ptr);
 
	uint height = png_get_image_height(png_ptr, info_ptr);
 

	
 
	/* Check if image dimensions don't overflow a size_t to avoid memory corruption. */
 
	if ((uint64)width * height >= (size_t)-1) {
 
		ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR);
 
		fclose(fp);
 
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
		return false;
 
	}
 

	
 
	if (map != NULL) {
 
		*map = MallocT<byte>(png_get_image_width(png_ptr, info_ptr) * png_get_image_height(png_ptr, info_ptr));
 
		*map = MallocT<byte>(width * height);
 
		ReadHeightmapPNGImageData(*map, png_ptr, info_ptr);
 
	}
 

	
 
	*x = png_get_image_width(png_ptr, info_ptr);
 
	*y = png_get_image_height(png_ptr, info_ptr);
 
	*x = width;
 
	*y = height;
 

	
 
	fclose(fp);
 
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
	return true;
 
}
 

	
 
#endif /* WITH_PNG */
 

	
 

	
 
/**
 
 * The BMP Heightmap loader.
 
 */
 
@@ -234,24 +245,32 @@ static bool ReadHeightmapBMP(char *filen
 
		return false;
 
	}
 

	
 
	BmpInitializeBuffer(&buffer, f);
 

	
 
	if (!BmpReadHeader(&buffer, &info, &data)) {
 
		ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR);
 
		fclose(f);
 
		BmpDestroyData(&data);
 
		return false;
 
	}
 

	
 
	/* Check if image dimensions don't overflow a size_t to avoid memory corruption. */
 
	if ((uint64)info.width * info.height >= (size_t)-1 / (info.bpp == 24 ? 3 : 1)) {
 
		ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR);
 
		fclose(f);
 
		BmpDestroyData(&data);
 
		return false;
 
	}
 

	
 
	if (map != NULL) {
 
		if (!BmpReadBitmap(&buffer, &info, &data)) {
 
			ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR);
 
			fclose(f);
 
			BmpDestroyData(&data);
 
			return false;
 
		}
 

	
 
		*map = MallocT<byte>(info.width * info.height);
 
		ReadHeightmapBMPImageData(*map, &info, &data);
 
	}
 

	
src/lang/english.txt
Show inline comments
 
@@ -3443,24 +3443,26 @@ STR_WARNING_LOADGAME_REMOVED_TRAMS      
 
# Map generation messages
 
STR_ERROR_COULD_NOT_CREATE_TOWN                                 :{WHITE}Map generation aborted...{}... no suitable town locations
 
STR_ERROR_NO_TOWN_IN_SCENARIO                                   :{WHITE}... there is no town in this scenario
 

	
 
STR_ERROR_PNGMAP                                                :{WHITE}Can't load landscape from PNG...
 
STR_ERROR_PNGMAP_FILE_NOT_FOUND                                 :{WHITE}... file not found
 
STR_ERROR_PNGMAP_IMAGE_TYPE                                     :{WHITE}... could not convert image type. 8 or 24-bit PNG image needed
 
STR_ERROR_PNGMAP_MISC                                           :{WHITE}... something just went wrong (probably corrupted file)
 

	
 
STR_ERROR_BMPMAP                                                :{WHITE}Can't load landscape from BMP...
 
STR_ERROR_BMPMAP_IMAGE_TYPE                                     :{WHITE}... could not convert image type
 

	
 
STR_ERROR_HEIGHTMAP_TOO_LARGE                                   :{WHITE}... image is too large
 

	
 
STR_WARNING_HEIGHTMAP_SCALE_CAPTION                             :{WHITE}Scale warning
 
STR_WARNING_HEIGHTMAP_SCALE_MESSAGE                             :{YELLOW}Resizing source map too much is not recommended. Continue with the generation?
 

	
 
# Soundset messages
 
STR_WARNING_FALLBACK_SOUNDSET                                   :{WHITE}Only a fallback sound set was found. If you want sounds, install a sound set via the content download system
 

	
 
# Screenshot related messages
 
STR_MESSAGE_SCREENSHOT_SUCCESSFULLY                             :{WHITE}Screenshot successfully saved as '{RAW_STRING}'
 
STR_ERROR_SCREENSHOT_FAILED                                     :{WHITE}Screenshot failed!
 

	
 
# Error message titles
 
STR_ERROR_MESSAGE_CAPTION                                       :{YELLOW}Message
src/spriteloader/png.cpp
Show inline comments
 
@@ -99,32 +99,43 @@ static bool LoadPNG(SpriteLoader::Sprite
 
		png_textp text_ptr;
 
		int num_text = 0;
 
		png_get_text(png_ptr, info_ptr, &text_ptr, &num_text);
 
		if (num_text == 0) DEBUG(misc, 0, "Warning: PNG Sprite '%s/%d.png' doesn't have x_offs and y_offs; expect graphical problems", filename, id);
 
		for (int i = 0; i < num_text; i++) {
 
			/* x_offs and y_offs are in the text-chunk of PNG */
 
			if (strcmp("x_offs", text_ptr[i].key) == 0) sprite->x_offs = strtol(text_ptr[i].text, NULL, 0);
 
			if (strcmp("y_offs", text_ptr[i].key) == 0) sprite->y_offs = strtol(text_ptr[i].text, NULL, 0);
 
		}
 

	
 
		sprite->height = png_get_image_height(png_ptr, info_ptr);
 
		sprite->width  = png_get_image_width(png_ptr, info_ptr);
 
		/* Check if sprite dimensions aren't larger than what is allowed in GRF-files. */
 
		if (sprite->height > UINT8_MAX || sprite->width > UINT16_MAX) {
 
			png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 
			return false;
 
		}
 
		sprite->AllocateData(sprite->width * sprite->height);
 
	} else if (sprite->height != png_get_image_height(png_ptr, info_ptr) || sprite->width != png_get_image_width(png_ptr, info_ptr)) {
 
		/* Make sure the mask image isn't larger than the sprite image. */
 
		DEBUG(misc, 0, "Ignoring mask for SpriteID %d as it isn't the same dimension as the masked sprite", id);
 
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 
		return true;
 
	}
 

	
 
	bit_depth  = png_get_bit_depth(png_ptr, info_ptr);
 
	colour_type = png_get_color_type(png_ptr, info_ptr);
 

	
 
	if (mask && (bit_depth != 8 || colour_type != PNG_COLOR_TYPE_PALETTE)) {
 
		DEBUG(misc, 0, "Ignoring mask for SpriteID %d as it isn't a 8 bit palette image", id);
 
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 
		return true;
 
	}
 

	
 
	if (!mask) {
 
		if (bit_depth == 16) png_set_strip_16(png_ptr);
 

	
 
		if (colour_type == PNG_COLOR_TYPE_PALETTE) {
 
			png_set_palette_to_rgb(png_ptr);
 
			colour_type = PNG_COLOR_TYPE_RGB;
 
		}
 
		if (colour_type == PNG_COLOR_TYPE_GRAY || colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
 
			png_set_gray_to_rgb(png_ptr);
0 comments (0 inline, 0 general)