mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-17 11:35:08 -04:00
If the server sends corrupted compressed map data, try to disconnect the game instead of outright crashing
This commit is contained in:
parent
c968d14a75
commit
dcf1b9a49e
@ -377,7 +377,7 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) {
|
|||||||
trnsCol = BITMAPCOL_BLACK;
|
trnsCol = BITMAPCOL_BLACK;
|
||||||
for (i = 0; i < PNG_PALETTE; i++) { palette[i] = BITMAPCOL_BLACK; }
|
for (i = 0; i < PNG_PALETTE; i++) { palette[i] = BITMAPCOL_BLACK; }
|
||||||
|
|
||||||
Inflate_MakeStream(&compStream, &inflate, stream);
|
Inflate_MakeStream2(&compStream, &inflate, stream);
|
||||||
ZLibHeader_Init(&zlibHeader);
|
ZLibHeader_Init(&zlibHeader);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -154,6 +154,8 @@ enum INFLATE_STATE_ {
|
|||||||
#define Inflate_UNSAFE_EnsureBits(state, bitsCount) while (state->NumBits < bitsCount) { Inflate_GetByte(state); }
|
#define Inflate_UNSAFE_EnsureBits(state, bitsCount) while (state->NumBits < bitsCount) { Inflate_GetByte(state); }
|
||||||
/* Peeks then consumes given bits */
|
/* Peeks then consumes given bits */
|
||||||
#define Inflate_ReadBits(state, bitsCount) Inflate_PeekBits(state, bitsCount); Inflate_ConsumeBits(state, bitsCount);
|
#define Inflate_ReadBits(state, bitsCount) Inflate_PeekBits(state, bitsCount); Inflate_ConsumeBits(state, bitsCount);
|
||||||
|
/* Sets to given result and sets state to DONE */
|
||||||
|
#define Inflate_Fail(state, res) state->result = res; state->State = INFLATE_STATE_DONE;
|
||||||
|
|
||||||
/* Goes to the next state, after having read data of a block */
|
/* Goes to the next state, after having read data of a block */
|
||||||
#define Inflate_NextBlockState(state) (state->LastBlock ? INFLATE_STATE_DONE : INFLATE_STATE_HEADER)
|
#define Inflate_NextBlockState(state) (state->LastBlock ? INFLATE_STATE_DONE : INFLATE_STATE_HEADER)
|
||||||
@ -329,7 +331,7 @@ static int Huffman_Unsafe_Decode_Slow(struct InflateState* state, struct Huffman
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inflate_Init(struct InflateState* state, struct Stream* source) {
|
void Inflate_Init2(struct InflateState* state, struct Stream* source) {
|
||||||
state->State = INFLATE_STATE_HEADER;
|
state->State = INFLATE_STATE_HEADER;
|
||||||
state->LastBlock = false;
|
state->LastBlock = false;
|
||||||
state->Bits = 0;
|
state->Bits = 0;
|
||||||
@ -340,6 +342,7 @@ void Inflate_Init(struct InflateState* state, struct Stream* source) {
|
|||||||
state->AvailOut = 0;
|
state->AvailOut = 0;
|
||||||
state->Source = source;
|
state->Source = source;
|
||||||
state->WindowIndex = 0;
|
state->WindowIndex = 0;
|
||||||
|
state->result = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const cc_uint8 fixed_lits[INFLATE_MAX_LITS] = {
|
static const cc_uint8 fixed_lits[INFLATE_MAX_LITS] = {
|
||||||
@ -496,7 +499,7 @@ void Inflate_Process(struct InflateState* state) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 3: {
|
case 3: {
|
||||||
Logger_Abort("DEFLATE - Invalid block type");
|
Inflate_Fail(state, INF_ERR_BLOCKTYPE);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -509,7 +512,8 @@ void Inflate_Process(struct InflateState* state) {
|
|||||||
nlen = Inflate_ReadBits(state, 16);
|
nlen = Inflate_ReadBits(state, 16);
|
||||||
|
|
||||||
if (len != (nlen ^ 0xFFFFUL)) {
|
if (len != (nlen ^ 0xFFFFUL)) {
|
||||||
Logger_Abort("DEFLATE - Uncompressed block LEN check failed");
|
Inflate_Fail(state, INF_ERR_BLOCKTYPE);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
state->Index = len; /* Reuse for 'uncompressed length' */
|
state->Index = len; /* Reuse for 'uncompressed length' */
|
||||||
state->State = INFLATE_STATE_UNCOMPRESSED_DATA;
|
state->State = INFLATE_STATE_UNCOMPRESSED_DATA;
|
||||||
@ -602,7 +606,7 @@ void Inflate_Process(struct InflateState* state) {
|
|||||||
case 16:
|
case 16:
|
||||||
Inflate_EnsureBits(state, 2);
|
Inflate_EnsureBits(state, 2);
|
||||||
repeatCount = Inflate_ReadBits(state, 2);
|
repeatCount = Inflate_ReadBits(state, 2);
|
||||||
if (!state->Index) Logger_Abort("DEFLATE - Tried to repeat invalid byte");
|
if (!state->Index) { Inflate_Fail(state, INF_ERR_REPEAT_BEG); return; }
|
||||||
repeatCount += 3; repeatValue = state->Buffer[state->Index - 1];
|
repeatCount += 3; repeatValue = state->Buffer[state->Index - 1];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -621,7 +625,8 @@ void Inflate_Process(struct InflateState* state) {
|
|||||||
|
|
||||||
count = state->NumLits + state->NumDists;
|
count = state->NumLits + state->NumDists;
|
||||||
if (state->Index + repeatCount > count) {
|
if (state->Index + repeatCount > count) {
|
||||||
Logger_Abort("DEFLATE - Tried to repeat past end");
|
Inflate_Fail(state, INF_ERR_REPEAT_END);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mem_Set(&state->Buffer[state->Index], repeatValue, repeatCount);
|
Mem_Set(&state->Buffer[state->Index], repeatValue, repeatCount);
|
||||||
@ -723,7 +728,7 @@ static cc_result Inflate_StreamRead(struct Stream* stream, cc_uint8* data, cc_ui
|
|||||||
|
|
||||||
hasInput = true;
|
hasInput = true;
|
||||||
while (state->AvailOut > 0 && hasInput) {
|
while (state->AvailOut > 0 && hasInput) {
|
||||||
if (state->State == INFLATE_STATE_DONE) break;
|
if (state->State == INFLATE_STATE_DONE) return state->result;
|
||||||
|
|
||||||
if (!state->AvailIn) {
|
if (!state->AvailIn) {
|
||||||
/* Fully used up input buffer. Cycle back to start. */
|
/* Fully used up input buffer. Cycle back to start. */
|
||||||
@ -748,9 +753,9 @@ static cc_result Inflate_StreamRead(struct Stream* stream, cc_uint8* data, cc_ui
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inflate_MakeStream(struct Stream* stream, struct InflateState* state, struct Stream* underlying) {
|
void Inflate_MakeStream2(struct Stream* stream, struct InflateState* state, struct Stream* underlying) {
|
||||||
Stream_Init(stream);
|
Stream_Init(stream);
|
||||||
Inflate_Init(state, underlying);
|
Inflate_Init2(state, underlying);
|
||||||
stream->Meta.Inflate = state;
|
stream->Meta.Inflate = state;
|
||||||
stream->Read = Inflate_StreamRead;
|
stream->Read = Inflate_StreamRead;
|
||||||
}
|
}
|
||||||
@ -1151,7 +1156,7 @@ static cc_result Zip_ReadLocalFileHeader(struct ZipState* state, struct ZipEntry
|
|||||||
return state->ProcessEntry(&path, &portion, state);
|
return state->ProcessEntry(&path, &portion, state);
|
||||||
} else if (method == 8) {
|
} else if (method == 8) {
|
||||||
Stream_ReadonlyPortion(&portion, stream, compressedSize);
|
Stream_ReadonlyPortion(&portion, stream, compressedSize);
|
||||||
Inflate_MakeStream(&compStream, &inflate, &portion);
|
Inflate_MakeStream2(&compStream, &inflate, &portion);
|
||||||
return state->ProcessEntry(&path, &compStream, state);
|
return state->ProcessEntry(&path, &compStream, state);
|
||||||
} else {
|
} else {
|
||||||
Platform_Log1("Unsupported.zip entry compression method: %i", &method);
|
Platform_Log1("Unsupported.zip entry compression method: %i", &method);
|
||||||
|
@ -64,17 +64,18 @@ struct InflateState {
|
|||||||
} Table; /* union to save on memory */
|
} Table; /* union to save on memory */
|
||||||
struct HuffmanTable TableDists; /* Values represent distances back */
|
struct HuffmanTable TableDists; /* Values represent distances back */
|
||||||
cc_uint8 Window[INFLATE_WINDOW_SIZE]; /* Holds circular buffer of recent output data, used for LZ77 */
|
cc_uint8 Window[INFLATE_WINDOW_SIZE]; /* Holds circular buffer of recent output data, used for LZ77 */
|
||||||
|
cc_result result;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Initialises DEFLATE decompressor state to defaults. */
|
/* Initialises DEFLATE decompressor state to defaults. */
|
||||||
CC_API void Inflate_Init(struct InflateState* state, struct Stream* source);
|
CC_API void Inflate_Init2(struct InflateState* state, struct Stream* source);
|
||||||
/* Attempts to decompress as much of the currently pending data as possible. */
|
/* Attempts to decompress as much of the currently pending data as possible. */
|
||||||
/* NOTE: This is a low level call - usually you treat as a stream via Inflate_MakeStream. */
|
/* NOTE: This is a low level call - usually you treat as a stream via Inflate_MakeStream. */
|
||||||
void Inflate_Process(struct InflateState* state);
|
void Inflate_Process(struct InflateState* state);
|
||||||
/* Deompresses input data read from another stream using DEFLATE. Read only stream. */
|
/* Deompresses input data read from another stream using DEFLATE. Read only stream. */
|
||||||
/* NOTE: This only uncompresses pure DEFLATE compressed data. */
|
/* NOTE: This only uncompresses pure DEFLATE compressed data. */
|
||||||
/* If data starts with a GZIP or ZLIB header, use GZipHeader_Read or ZLibHeader_Read to first skip it. */
|
/* If data starts with a GZIP or ZLIB header, use GZipHeader_Read or ZLibHeader_Read to first skip it. */
|
||||||
CC_API void Inflate_MakeStream(struct Stream* stream, struct InflateState* state, struct Stream* underlying);
|
CC_API void Inflate_MakeStream2(struct Stream* stream, struct InflateState* state, struct Stream* underlying);
|
||||||
|
|
||||||
|
|
||||||
#define DEFLATE_BLOCK_SIZE 16384
|
#define DEFLATE_BLOCK_SIZE 16384
|
||||||
|
@ -49,6 +49,8 @@ enum ERRORS_ALL {
|
|||||||
/* CW map decoding errors */
|
/* CW map decoding errors */
|
||||||
NBT_ERR_INT32S, NBT_ERR_UNKNOWN, CW_ERR_ROOT_TAG, CW_ERR_STRING_LEN,
|
NBT_ERR_INT32S, NBT_ERR_UNKNOWN, CW_ERR_ROOT_TAG, CW_ERR_STRING_LEN,
|
||||||
/* OpenAL initing errors */
|
/* OpenAL initing errors */
|
||||||
AL_ERR_INIT_DEVICE, AL_ERR_INIT_CONTEXT
|
AL_ERR_INIT_DEVICE, AL_ERR_INIT_CONTEXT,
|
||||||
|
/* Inflate errors */
|
||||||
|
INF_ERR_BLOCKTYPE, INF_ERR_LEN_VERIFY, INF_ERR_REPEAT_BEG, INF_ERR_REPEAT_END
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -166,7 +166,7 @@ cc_result Lvl_Load(struct Stream* stream) {
|
|||||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||||
struct Stream compStream;
|
struct Stream compStream;
|
||||||
struct InflateState state;
|
struct InflateState state;
|
||||||
Inflate_MakeStream(&compStream, &state, stream);
|
Inflate_MakeStream2(&compStream, &state, stream);
|
||||||
|
|
||||||
if ((res = Map_SkipGZipHeader(stream))) return res;
|
if ((res = Map_SkipGZipHeader(stream))) return res;
|
||||||
if ((res = Stream_Read(&compStream, header, sizeof(header)))) return res;
|
if ((res = Stream_Read(&compStream, header, sizeof(header)))) return res;
|
||||||
@ -241,7 +241,7 @@ cc_result Fcm_Load(struct Stream* stream) {
|
|||||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||||
struct Stream compStream;
|
struct Stream compStream;
|
||||||
struct InflateState state;
|
struct InflateState state;
|
||||||
Inflate_MakeStream(&compStream, &state, stream);
|
Inflate_MakeStream2(&compStream, &state, stream);
|
||||||
|
|
||||||
if ((res = Stream_Read(stream, header, sizeof(header)))) return res;
|
if ((res = Stream_Read(stream, header, sizeof(header)))) return res;
|
||||||
if (Stream_GetU32_LE(&header[0]) != 0x0FC2AF40UL) return FCM_ERR_IDENTIFIER;
|
if (Stream_GetU32_LE(&header[0]) != 0x0FC2AF40UL) return FCM_ERR_IDENTIFIER;
|
||||||
@ -690,7 +690,7 @@ cc_result Cw_Load(struct Stream* stream) {
|
|||||||
Vec3* spawn; IVec3 pos;
|
Vec3* spawn; IVec3 pos;
|
||||||
cc_result res;
|
cc_result res;
|
||||||
|
|
||||||
Inflate_MakeStream(&compStream, &state, stream);
|
Inflate_MakeStream2(&compStream, &state, stream);
|
||||||
if ((res = Map_SkipGZipHeader(stream))) return res;
|
if ((res = Map_SkipGZipHeader(stream))) return res;
|
||||||
if ((res = compStream.ReadU8(&compStream, &tag))) return res;
|
if ((res = compStream.ReadU8(&compStream, &tag))) return res;
|
||||||
|
|
||||||
@ -899,7 +899,7 @@ cc_result Dat_Load(struct Stream* stream) {
|
|||||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||||
struct Stream compStream;
|
struct Stream compStream;
|
||||||
struct InflateState state;
|
struct InflateState state;
|
||||||
Inflate_MakeStream(&compStream, &state, stream);
|
Inflate_MakeStream2(&compStream, &state, stream);
|
||||||
|
|
||||||
if ((res = Map_SkipGZipHeader(stream))) return res;
|
if ((res = Map_SkipGZipHeader(stream))) return res;
|
||||||
if ((res = Stream_Read(&compStream, header, sizeof(header)))) return res;
|
if ((res = Stream_Read(&compStream, header, sizeof(header)))) return res;
|
||||||
|
@ -409,8 +409,18 @@ static void Classic_Handshake(cc_uint8* data) {
|
|||||||
|
|
||||||
static void Classic_Ping(cc_uint8* data) { }
|
static void Classic_Ping(cc_uint8* data) { }
|
||||||
|
|
||||||
|
#define MAP_SIZE_LEN 4
|
||||||
|
static void DisconnectInvalidMap(cc_result res) {
|
||||||
|
static const String title = String_FromConst("Disconnected");
|
||||||
|
String tmp; char tmpBuffer[STRING_SIZE];
|
||||||
|
String_InitArray(tmp, tmpBuffer);
|
||||||
|
|
||||||
|
String_Format1(&tmp, "Server sent corrupted map data (error %h)", &res);
|
||||||
|
Game_Disconnect(&title, &tmp); return;
|
||||||
|
}
|
||||||
|
|
||||||
static void MapState_Init(struct MapState* m) {
|
static void MapState_Init(struct MapState* m) {
|
||||||
Inflate_MakeStream(&m->stream, &m->inflateState, &map_part);
|
Inflate_MakeStream2(&m->stream, &m->inflateState, &map_part);
|
||||||
m->index = 0;
|
m->index = 0;
|
||||||
m->blocks = NULL;
|
m->blocks = NULL;
|
||||||
m->allocFailed = false;
|
m->allocFailed = false;
|
||||||
@ -427,6 +437,7 @@ static void FreeMapStates(void) {
|
|||||||
|
|
||||||
static void MapState_Read(struct MapState* m) {
|
static void MapState_Read(struct MapState* m) {
|
||||||
cc_uint32 left, read;
|
cc_uint32 left, read;
|
||||||
|
cc_result res;
|
||||||
if (m->allocFailed) return;
|
if (m->allocFailed) return;
|
||||||
|
|
||||||
if (!m->blocks) {
|
if (!m->blocks) {
|
||||||
@ -440,7 +451,9 @@ static void MapState_Read(struct MapState* m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
left = map_volume - m->index;
|
left = map_volume - m->index;
|
||||||
m->stream.Read(&m->stream, &m->blocks[m->index], left, &read);
|
res = m->stream.Read(&m->stream, &m->blocks[m->index], left, &read);
|
||||||
|
|
||||||
|
if (res) DisconnectInvalidMap(res);
|
||||||
m->index += read;
|
m->index += read;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,16 +484,7 @@ static void Classic_LevelInit(cc_uint8* data) {
|
|||||||
/* Fast map puts volume in header, and uses raw DEFLATE without GZIP header/footer */
|
/* Fast map puts volume in header, and uses raw DEFLATE without GZIP header/footer */
|
||||||
map_volume = Stream_GetU32_BE(data);
|
map_volume = Stream_GetU32_BE(data);
|
||||||
map_gzHeader.done = true;
|
map_gzHeader.done = true;
|
||||||
map_sizeIndex = 4;
|
map_sizeIndex = MAP_SIZE_LEN;
|
||||||
}
|
|
||||||
|
|
||||||
static void DisconnectInvalidMap(cc_result res) {
|
|
||||||
static const String title = String_FromConst("Disconnected");
|
|
||||||
String tmp; char tmpBuffer[STRING_SIZE];
|
|
||||||
String_InitArray(tmp, tmpBuffer);
|
|
||||||
|
|
||||||
String_Format1(&tmp, "Server sent corrupted map data (error %h)", &res);
|
|
||||||
Game_Disconnect(&title, &tmp); return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Classic_LevelDataChunk(cc_uint8* data) {
|
static void Classic_LevelDataChunk(cc_uint8* data) {
|
||||||
@ -508,13 +512,15 @@ static void Classic_LevelDataChunk(cc_uint8* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (map_gzHeader.done) {
|
if (map_gzHeader.done) {
|
||||||
if (map_sizeIndex < 4) {
|
if (map_sizeIndex < MAP_SIZE_LEN) {
|
||||||
left = 4 - map_sizeIndex;
|
left = MAP_SIZE_LEN - map_sizeIndex;
|
||||||
map.stream.Read(&map.stream, &map_size[map_sizeIndex], left, &read);
|
res = map.stream.Read(&map.stream, &map_size[map_sizeIndex], left, &read);
|
||||||
|
|
||||||
|
if (res) { DisconnectInvalidMap(res); return; }
|
||||||
map_sizeIndex += read;
|
map_sizeIndex += read;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map_sizeIndex == 4) {
|
if (map_sizeIndex == MAP_SIZE_LEN) {
|
||||||
if (!map_volume) map_volume = Stream_GetU32_BE(map_size);
|
if (!map_volume) map_volume = Stream_GetU32_BE(map_size);
|
||||||
|
|
||||||
#ifndef EXTENDED_BLOCKS
|
#ifndef EXTENDED_BLOCKS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user