Commit 893a96ed authored by Chen Bill's avatar Chen Bill

add boundary check to STOC_CHAT packet

parent 2b5c12f3
......@@ -780,12 +780,16 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
break;
}
case STOC_CHAT: {
if (len != 1 + (int)sizeof(STOC_Chat))
const int chat_msg_size = len - 1 - sizeof(uint16_t);
if (!check_msg_size(chat_msg_size))
return;
STOC_Chat packet;
std::memcpy(&packet, pdata, sizeof packet);
const auto* pkt = &packet;
int player = pkt->player;
uint16_t chat_player_type = buffer_read<uint16_t>(pdata);
uint16_t chat_msg[LEN_CHAT_MSG];
buffer_read_block(pdata, chat_msg, chat_msg_size);
const int chat_msg_len = chat_msg_size / sizeof(uint16_t);
if (chat_msg[chat_msg_len - 1] != 0)
return;
int player = chat_player_type;
auto play_sound = false;
if(player < 4) {
if(mainGame->chkIgnore1->isChecked())
......@@ -805,8 +809,9 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
player = 10;
}
}
wchar_t msg[256];
BufferIO::CopyWStr(pkt->msg, msg, 256);
// UTF-16 to wchar_t
wchar_t msg[LEN_CHAT_MSG];
BufferIO::CopyWStr(chat_msg, msg, LEN_CHAT_MSG);
mainGame->gMutex.lock();
mainGame->AddChatMsg(msg, player, play_sound);
mainGame->gMutex.unlock();
......
......@@ -5,11 +5,6 @@
#include <vector>
#include <set>
#include <utility>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/thread.h>
#include "network.h"
#include "data_manager.h"
#include "deck_manager.h"
......
......@@ -2028,9 +2028,9 @@ bool ClientField::OnCommonEvent(const irr::SEvent& event) {
break;
const wchar_t* input = mainGame->ebChatInput->getText();
if(input[0]) {
unsigned short msgbuf[256];
int len = BufferIO::CopyWStr(input, msgbuf, 256);
DuelClient::SendBufferToServer(CTOS_CHAT, msgbuf, (len + 1) * sizeof(short));
uint16_t msgbuf[LEN_CHAT_MSG];
int len = BufferIO::CopyWStr(input, msgbuf, LEN_CHAT_MSG);
DuelClient::SendBufferToServer(CTOS_CHAT, msgbuf, (len + 1) * sizeof(uint16_t));
mainGame->ebChatInput->setText(L"");
return true;
}
......
......@@ -350,5 +350,19 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
}
}
}
size_t NetServer::CreateChatPacket(unsigned char* src, int src_size, unsigned char* dst, uint16_t dst_player_type) {
if (!check_msg_size(src_size))
return 0;
uint16_t src_msg[LEN_CHAT_MSG];
std::memcpy(src_msg, src, src_size);
const int src_len = src_size / sizeof(uint16_t);
if (src_msg[src_len - 1] != 0)
return 0;
// STOC_Chat packet
auto pdst = dst;
buffer_write<uint16_t>(pdst, dst_player_type);
buffer_write_block(pdst, src_msg, src_size);
return sizeof(dst_player_type) + src_size;
}
}
......@@ -37,6 +37,7 @@ public:
static int ServerThread();
static void DisconnectPlayer(DuelPlayer* dp);
static void HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len);
static size_t CreateChatPacket(unsigned char* src, int src_size, unsigned char* dst, uint16_t dst_player_type);
static void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto) {
auto p = net_server_write;
BufferIO::WriteInt16(p, 1);
......
......@@ -58,6 +58,8 @@ struct CTOS_JoinGame {
struct CTOS_Kick {
unsigned char pos;
};
// STOC
struct STOC_ErrorMsg {
unsigned char msg;
unsigned int code;
......@@ -82,10 +84,14 @@ struct STOC_TimeLimit {
unsigned char player;
unsigned short left_time;
};
struct STOC_Chat {
unsigned short player;
unsigned short msg[256];
};
/*
* STOC_Chat
* uint16_t player_type;
* uint16_t msg[256]; (UTF-16 string)
*/
constexpr int LEN_CHAT_PLAYER = 1;
constexpr int LEN_CHAT_MSG = 256;
constexpr int SIZE_STOC_CHAT = (LEN_CHAT_PLAYER + LEN_CHAT_MSG) * sizeof(uint16_t);
struct STOC_HS_PlayerEnter {
unsigned short name[20];
unsigned char pos;
......@@ -108,11 +114,22 @@ struct DuelPlayer {
bufferevent* bev{ 0 };
};
inline bool check_msg_size(int size) {
// empty string is not allowed
if (size < 2* sizeof(uint16_t))
return false;
if (size > LEN_CHAT_MSG * sizeof(uint16_t))
return false;
if (size % sizeof(uint16_t) != 0)
return false;
return true;
}
class DuelMode {
public:
DuelMode(): host_player(nullptr), pduel(0), duel_stage(0) {}
virtual ~DuelMode() {}
virtual void Chat(DuelPlayer* dp, void* pdata, int len) {}
virtual void Chat(DuelPlayer* dp, unsigned char* pdata, int len) {}
virtual void JoinGame(DuelPlayer* dp, void* pdata, bool is_creater) {}
virtual void LeaveGame(DuelPlayer* dp) {}
virtual void ToDuelist(DuelPlayer* dp) {}
......
......@@ -12,12 +12,12 @@ SingleDuel::SingleDuel(bool is_match) {
}
SingleDuel::~SingleDuel() {
}
void SingleDuel::Chat(DuelPlayer* dp, void* pdata, int len) {
STOC_Chat scc;
scc.player = dp->type;
unsigned short* msg = (unsigned short*)pdata;
int msglen = BufferIO::CopyWStr(msg, scc.msg, 256);
NetServer::SendBufferToPlayer(players[0], STOC_CHAT, &scc, 4 + msglen * 2);
void SingleDuel::Chat(DuelPlayer* dp, unsigned char* pdata, int len) {
unsigned char scc[SIZE_STOC_CHAT];
const auto scc_size = NetServer::CreateChatPacket(pdata, len, scc, dp->type);
if (!scc_size)
return;
NetServer::SendBufferToPlayer(players[0], STOC_CHAT, scc, scc_size);
NetServer::ReSendToPlayer(players[1]);
for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit);
......
......@@ -11,7 +11,7 @@ class SingleDuel: public DuelMode {
public:
SingleDuel(bool is_match);
virtual ~SingleDuel();
virtual void Chat(DuelPlayer* dp, void* pdata, int len);
virtual void Chat(DuelPlayer* dp, unsigned char* pdata, int len);
virtual void JoinGame(DuelPlayer* dp, void* pdata, bool is_creater);
virtual void LeaveGame(DuelPlayer* dp);
virtual void ToDuelist(DuelPlayer* dp);
......
......@@ -16,13 +16,13 @@ TagDuel::TagDuel() {
}
TagDuel::~TagDuel() {
}
void TagDuel::Chat(DuelPlayer* dp, void* pdata, int len) {
STOC_Chat scc;
scc.player = dp->type;
unsigned short* msg = (unsigned short*)pdata;
int msglen = BufferIO::CopyWStr(msg, scc.msg, 256);
void TagDuel::Chat(DuelPlayer* dp, unsigned char* pdata, int len) {
unsigned char scc[SIZE_STOC_CHAT];
const auto scc_size = NetServer::CreateChatPacket(pdata, len, scc, dp->type);
if (!scc_size)
return;
for(int i = 0; i < 4; ++i)
NetServer::SendBufferToPlayer(players[i], STOC_CHAT, &scc, 4 + msglen * 2);
NetServer::SendBufferToPlayer(players[i], STOC_CHAT, scc, scc_size);
for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit);
}
......
......@@ -11,7 +11,7 @@ class TagDuel: public DuelMode {
public:
TagDuel();
virtual ~TagDuel();
virtual void Chat(DuelPlayer* dp, void* pdata, int len);
virtual void Chat(DuelPlayer* dp, unsigned char* pdata, int len);
virtual void JoinGame(DuelPlayer* dp, void* pdata, bool is_creater);
virtual void LeaveGame(DuelPlayer* dp);
virtual void ToDuelist(DuelPlayer* dp);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment