fix #3558: safely read chunks from S6 files

It appears many saved games have been saved with excess uncompressed data that overflows the S6 structure. This may have been caused by a save bug in an earlier version of OpenRCT2. This will now cap the uncompressed data to the amount expected.
This commit is contained in:
Ted John 2016-05-10 21:39:12 +01:00
parent d979e2b607
commit 4298f416d2
3 changed files with 34 additions and 18 deletions

View File

@ -107,7 +107,7 @@ void S6Importer::LoadSavedGame(SDL_RWops *rw)
{
auto meh = SDL_RWtell(rw);
sawyercoding_read_chunk(rw, (uint8*)&_s6.header);
sawyercoding_read_chunk_safe(rw, &_s6.header, sizeof(_s6.header));
if (_s6.header.type != S6_TYPE_SAVEDGAME)
{
throw Exception("Data is not a saved game.");
@ -127,21 +127,21 @@ void S6Importer::LoadSavedGame(SDL_RWops *rw)
}
}
sawyercoding_read_chunk(rw, (uint8*)&_s6.objects);
sawyercoding_read_chunk(rw, (uint8*)&_s6.elapsed_months);
sawyercoding_read_chunk(rw, (uint8*)&_s6.map_elements);
sawyercoding_read_chunk(rw, (uint8*)&_s6.dword_010E63B8);
sawyercoding_read_chunk_safe(rw, &_s6.objects, sizeof(_s6.objects));
sawyercoding_read_chunk_safe(rw, &_s6.elapsed_months, 16);
sawyercoding_read_chunk_safe(rw, &_s6.map_elements, sizeof(_s6.map_elements));
sawyercoding_read_chunk_safe(rw, &_s6.dword_010E63B8, 3048816);
}
void S6Importer::LoadScenario(SDL_RWops *rw)
{
sawyercoding_read_chunk(rw, (uint8*)&_s6.header);
sawyercoding_read_chunk_safe(rw, &_s6.header, sizeof(_s6.header));
if (_s6.header.type != S6_TYPE_SCENARIO)
{
throw Exception("Data is not a scenario.");
}
sawyercoding_read_chunk(rw, (uint8*)&_s6.info);
sawyercoding_read_chunk_safe(rw, &_s6.info, sizeof(_s6.info));
// Read packed objects
// TODO try to contain this more and not store objects until later
@ -157,17 +157,17 @@ void S6Importer::LoadScenario(SDL_RWops *rw)
}
}
sawyercoding_read_chunk(rw, (uint8*)&_s6.objects);
sawyercoding_read_chunk(rw, (uint8*)&_s6.elapsed_months);
sawyercoding_read_chunk(rw, (uint8*)&_s6.map_elements);
sawyercoding_read_chunk(rw, (uint8*)&_s6.dword_010E63B8);
sawyercoding_read_chunk(rw, (uint8*)&_s6.guests_in_park);
sawyercoding_read_chunk(rw, (uint8*)&_s6.last_guests_in_park);
sawyercoding_read_chunk(rw, (uint8*)&_s6.park_rating);
sawyercoding_read_chunk(rw, (uint8*)&_s6.active_research_types);
sawyercoding_read_chunk(rw, (uint8*)&_s6.current_expenditure);
sawyercoding_read_chunk(rw, (uint8*)&_s6.park_value);
sawyercoding_read_chunk(rw, (uint8*)&_s6.completed_company_value);
sawyercoding_read_chunk_safe(rw, &_s6.objects, sizeof(_s6.objects));
sawyercoding_read_chunk_safe(rw, &_s6.elapsed_months, 16);
sawyercoding_read_chunk_safe(rw, &_s6.map_elements, sizeof(_s6.map_elements));
sawyercoding_read_chunk_safe(rw, &_s6.dword_010E63B8, 2560076);
sawyercoding_read_chunk_safe(rw, &_s6.guests_in_park, 4);
sawyercoding_read_chunk_safe(rw, &_s6.last_guests_in_park, 8);
sawyercoding_read_chunk_safe(rw, &_s6.park_rating, 2);
sawyercoding_read_chunk_safe(rw, &_s6.active_research_types, 1082);
sawyercoding_read_chunk_safe(rw, &_s6.current_expenditure, 16);
sawyercoding_read_chunk_safe(rw, &_s6.park_value, 4);
sawyercoding_read_chunk_safe(rw, &_s6.completed_company_value, 483816);
}
void S6Importer::Import()

View File

@ -80,6 +80,21 @@ int sawyercoding_validate_checksum(SDL_RWops* rw)
return checksum == fileChecksum;
}
bool sawyercoding_read_chunk_safe(SDL_RWops *rw, void *dst, size_t dstLength)
{
// Allocate 16 MB to store uncompressed data
uint8 *tempBuffer = malloc(16 * 1024 * 1024);
size_t uncompressedLength = sawyercoding_read_chunk(rw, tempBuffer);
if (uncompressedLength == SIZE_MAX) {
free(tempBuffer);
return false;
} else {
memcpy(dst, tempBuffer, min(dstLength, uncompressedLength));
free(tempBuffer);
return true;
}
}
/**
*
* rct2: 0x0067685F

View File

@ -46,6 +46,7 @@ enum {
int sawyercoding_validate_checksum(SDL_RWops* rw);
uint32 sawyercoding_calculate_checksum(const uint8* buffer, size_t length);
bool sawyercoding_read_chunk_safe(SDL_RWops *rw, void *dst, size_t dstLength);
size_t sawyercoding_read_chunk(SDL_RWops* rw, uint8 *buffer);
size_t sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader);
size_t sawyercoding_decode_sv4(const uint8 *src, uint8 *dst, size_t length);