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) { ...@@ -780,12 +780,16 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
break; break;
} }
case STOC_CHAT: { 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; return;
STOC_Chat packet; uint16_t chat_player_type = buffer_read<uint16_t>(pdata);
std::memcpy(&packet, pdata, sizeof packet); uint16_t chat_msg[LEN_CHAT_MSG];
const auto* pkt = &packet; buffer_read_block(pdata, chat_msg, chat_msg_size);
int player = pkt->player; 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; auto play_sound = false;
if(player < 4) { if(player < 4) {
if(mainGame->chkIgnore1->isChecked()) if(mainGame->chkIgnore1->isChecked())
...@@ -805,8 +809,9 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) { ...@@ -805,8 +809,9 @@ void DuelClient::HandleSTOCPacketLan(unsigned char* data, int len) {
player = 10; player = 10;
} }
} }
wchar_t msg[256]; // UTF-16 to wchar_t
BufferIO::CopyWStr(pkt->msg, msg, 256); wchar_t msg[LEN_CHAT_MSG];
BufferIO::CopyWStr(chat_msg, msg, LEN_CHAT_MSG);
mainGame->gMutex.lock(); mainGame->gMutex.lock();
mainGame->AddChatMsg(msg, player, play_sound); mainGame->AddChatMsg(msg, player, play_sound);
mainGame->gMutex.unlock(); mainGame->gMutex.unlock();
......
...@@ -5,11 +5,6 @@ ...@@ -5,11 +5,6 @@
#include <vector> #include <vector>
#include <set> #include <set>
#include <utility> #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 "network.h"
#include "data_manager.h" #include "data_manager.h"
#include "deck_manager.h" #include "deck_manager.h"
......
...@@ -2028,9 +2028,9 @@ bool ClientField::OnCommonEvent(const irr::SEvent& event) { ...@@ -2028,9 +2028,9 @@ bool ClientField::OnCommonEvent(const irr::SEvent& event) {
break; break;
const wchar_t* input = mainGame->ebChatInput->getText(); const wchar_t* input = mainGame->ebChatInput->getText();
if(input[0]) { if(input[0]) {
unsigned short msgbuf[256]; uint16_t msgbuf[LEN_CHAT_MSG];
int len = BufferIO::CopyWStr(input, msgbuf, 256); int len = BufferIO::CopyWStr(input, msgbuf, LEN_CHAT_MSG);
DuelClient::SendBufferToServer(CTOS_CHAT, msgbuf, (len + 1) * sizeof(short)); DuelClient::SendBufferToServer(CTOS_CHAT, msgbuf, (len + 1) * sizeof(uint16_t));
mainGame->ebChatInput->setText(L""); mainGame->ebChatInput->setText(L"");
return true; return true;
} }
......
...@@ -350,5 +350,19 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) { ...@@ -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: ...@@ -37,6 +37,7 @@ public:
static int ServerThread(); static int ServerThread();
static void DisconnectPlayer(DuelPlayer* dp); static void DisconnectPlayer(DuelPlayer* dp);
static void HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len); 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) { static void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto) {
auto p = net_server_write; auto p = net_server_write;
BufferIO::WriteInt16(p, 1); BufferIO::WriteInt16(p, 1);
......
...@@ -58,6 +58,8 @@ struct CTOS_JoinGame { ...@@ -58,6 +58,8 @@ struct CTOS_JoinGame {
struct CTOS_Kick { struct CTOS_Kick {
unsigned char pos; unsigned char pos;
}; };
// STOC
struct STOC_ErrorMsg { struct STOC_ErrorMsg {
unsigned char msg; unsigned char msg;
unsigned int code; unsigned int code;
...@@ -82,10 +84,14 @@ struct STOC_TimeLimit { ...@@ -82,10 +84,14 @@ struct STOC_TimeLimit {
unsigned char player; unsigned char player;
unsigned short left_time; unsigned short left_time;
}; };
struct STOC_Chat { /*
unsigned short player; * STOC_Chat
unsigned short msg[256]; * 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 { struct STOC_HS_PlayerEnter {
unsigned short name[20]; unsigned short name[20];
unsigned char pos; unsigned char pos;
...@@ -108,11 +114,22 @@ struct DuelPlayer { ...@@ -108,11 +114,22 @@ struct DuelPlayer {
bufferevent* bev{ 0 }; 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 { class DuelMode {
public: public:
DuelMode(): host_player(nullptr), pduel(0), duel_stage(0) {} DuelMode(): host_player(nullptr), pduel(0), duel_stage(0) {}
virtual ~DuelMode() {} 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 JoinGame(DuelPlayer* dp, void* pdata, bool is_creater) {}
virtual void LeaveGame(DuelPlayer* dp) {} virtual void LeaveGame(DuelPlayer* dp) {}
virtual void ToDuelist(DuelPlayer* dp) {} virtual void ToDuelist(DuelPlayer* dp) {}
......
...@@ -12,12 +12,12 @@ SingleDuel::SingleDuel(bool is_match) { ...@@ -12,12 +12,12 @@ SingleDuel::SingleDuel(bool is_match) {
} }
SingleDuel::~SingleDuel() { SingleDuel::~SingleDuel() {
} }
void SingleDuel::Chat(DuelPlayer* dp, void* pdata, int len) { void SingleDuel::Chat(DuelPlayer* dp, unsigned char* pdata, int len) {
STOC_Chat scc; unsigned char scc[SIZE_STOC_CHAT];
scc.player = dp->type; const auto scc_size = NetServer::CreateChatPacket(pdata, len, scc, dp->type);
unsigned short* msg = (unsigned short*)pdata; if (!scc_size)
int msglen = BufferIO::CopyWStr(msg, scc.msg, 256); return;
NetServer::SendBufferToPlayer(players[0], STOC_CHAT, &scc, 4 + msglen * 2); NetServer::SendBufferToPlayer(players[0], STOC_CHAT, scc, scc_size);
NetServer::ReSendToPlayer(players[1]); NetServer::ReSendToPlayer(players[1]);
for(auto pit = observers.begin(); pit != observers.end(); ++pit) for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit); NetServer::ReSendToPlayer(*pit);
......
...@@ -11,7 +11,7 @@ class SingleDuel: public DuelMode { ...@@ -11,7 +11,7 @@ class SingleDuel: public DuelMode {
public: public:
SingleDuel(bool is_match); SingleDuel(bool is_match);
virtual ~SingleDuel(); 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 JoinGame(DuelPlayer* dp, void* pdata, bool is_creater);
virtual void LeaveGame(DuelPlayer* dp); virtual void LeaveGame(DuelPlayer* dp);
virtual void ToDuelist(DuelPlayer* dp); virtual void ToDuelist(DuelPlayer* dp);
......
...@@ -16,13 +16,13 @@ TagDuel::TagDuel() { ...@@ -16,13 +16,13 @@ TagDuel::TagDuel() {
} }
TagDuel::~TagDuel() { TagDuel::~TagDuel() {
} }
void TagDuel::Chat(DuelPlayer* dp, void* pdata, int len) { void TagDuel::Chat(DuelPlayer* dp, unsigned char* pdata, int len) {
STOC_Chat scc; unsigned char scc[SIZE_STOC_CHAT];
scc.player = dp->type; const auto scc_size = NetServer::CreateChatPacket(pdata, len, scc, dp->type);
unsigned short* msg = (unsigned short*)pdata; if (!scc_size)
int msglen = BufferIO::CopyWStr(msg, scc.msg, 256); return;
for(int i = 0; i < 4; ++i) 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) for(auto pit = observers.begin(); pit != observers.end(); ++pit)
NetServer::ReSendToPlayer(*pit); NetServer::ReSendToPlayer(*pit);
} }
......
...@@ -11,7 +11,7 @@ class TagDuel: public DuelMode { ...@@ -11,7 +11,7 @@ class TagDuel: public DuelMode {
public: public:
TagDuel(); TagDuel();
virtual ~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 JoinGame(DuelPlayer* dp, void* pdata, bool is_creater);
virtual void LeaveGame(DuelPlayer* dp); virtual void LeaveGame(DuelPlayer* dp);
virtual void ToDuelist(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