mirror of https://github.com/PCSX2/pcsx2.git
IPC: return an error when packet is too big
This commit is contained in:
parent
a0aaad7ff8
commit
ad1cdc9122
110
pcsx2/IPC.cpp
110
pcsx2/IPC.cpp
|
@ -45,7 +45,6 @@ SocketIPC::SocketIPC(SysCoreThread* vm)
|
||||||
WSADATA wsa;
|
WSADATA wsa;
|
||||||
SOCKET new_socket;
|
SOCKET new_socket;
|
||||||
struct sockaddr_in server, client;
|
struct sockaddr_in server, client;
|
||||||
int c;
|
|
||||||
|
|
||||||
|
|
||||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
|
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
|
||||||
|
@ -120,6 +119,20 @@ SocketIPC::SocketIPC(SysCoreThread* vm)
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* SocketIPC::MakeOkIPC(char* ret_buffer, uint32_t size = 5)
|
||||||
|
{
|
||||||
|
ToArray<uint32_t>(ret_buffer, size, 0);
|
||||||
|
ret_buffer[4] = IPC_OK;
|
||||||
|
return ret_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* SocketIPC::MakeFailIPC(char* ret_buffer, uint32_t size = 5)
|
||||||
|
{
|
||||||
|
ToArray<uint32_t>(ret_buffer, size, 0);
|
||||||
|
ret_buffer[4] = IPC_FAIL;
|
||||||
|
return ret_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
void SocketIPC::ExecuteTaskInThread()
|
void SocketIPC::ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
m_end = false;
|
m_end = false;
|
||||||
|
@ -168,55 +181,49 @@ void SocketIPC::ExecuteTaskInThread()
|
||||||
|
|
||||||
// either int or ssize_t depending on the platform, so we have to
|
// either int or ssize_t depending on the platform, so we have to
|
||||||
// use a bunch of auto
|
// use a bunch of auto
|
||||||
auto receive_length = read_portable(m_msgsock, m_ipc_buffer, MAX_IPC_SIZE);
|
auto receive_length = 0;
|
||||||
if (receive_length > 0)
|
auto end_length = 4;
|
||||||
|
|
||||||
|
// while we haven't received the entire packet, maybe due to
|
||||||
|
// socket datagram splittage, we continue to read
|
||||||
|
while (receive_length < end_length)
|
||||||
{
|
{
|
||||||
// if we already received at least the length then we read it
|
auto tmp_length = read_portable(m_msgsock, &m_ipc_buffer[receive_length], MAX_IPC_SIZE - receive_length);
|
||||||
auto end_length = 4;
|
|
||||||
if (receive_length >= end_length)
|
// we close the connection if an error happens
|
||||||
|
if (tmp_length <= 0)
|
||||||
{
|
{
|
||||||
end_length = FromArray<u32>(m_ipc_buffer, 0);
|
receive_length = 0;
|
||||||
if (end_length > MAX_IPC_SIZE)
|
break;
|
||||||
end_length = MAX_IPC_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// while we haven't received the entire packet, maybe due to
|
receive_length += tmp_length;
|
||||||
// socket datagram splittage, we continue to read
|
|
||||||
while (receive_length < end_length)
|
|
||||||
{
|
|
||||||
auto tmp_length = read_portable(m_msgsock, &m_ipc_buffer[receive_length], MAX_IPC_SIZE - receive_length);
|
|
||||||
|
|
||||||
// we close the connection if an error happens
|
// if we got at least the final size then update
|
||||||
if (tmp_length <= 0)
|
if (end_length == 4 && receive_length >= 4)
|
||||||
|
{
|
||||||
|
end_length = FromArray<u32>(m_ipc_buffer, 0);
|
||||||
|
// we'd like to avoid a client trying to do OOB
|
||||||
|
if (end_length > MAX_IPC_SIZE)
|
||||||
{
|
{
|
||||||
receive_length = 0;
|
receive_length = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
receive_length += tmp_length;
|
|
||||||
|
|
||||||
// if we got at least the final size then update
|
|
||||||
if (end_length == 4 && receive_length >= 4)
|
|
||||||
{
|
|
||||||
end_length = FromArray<u32>(m_ipc_buffer, 0);
|
|
||||||
// we'd like to avoid a client trying to do OOB
|
|
||||||
if (end_length > MAX_IPC_SIZE)
|
|
||||||
end_length = MAX_IPC_SIZE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
SocketIPC::IPCBuffer res;
|
||||||
|
|
||||||
if (receive_length == 0)
|
// we remove 4 bytes to get the message size out of the IPC command
|
||||||
break;
|
// size in ParseCommand
|
||||||
|
if (receive_length == 0)
|
||||||
|
res = IPCBuffer{5, MakeFailIPC(m_ret_buffer)};
|
||||||
|
else
|
||||||
|
res = ParseCommand(&m_ipc_buffer[4], m_ret_buffer, (u32)receive_length - 4);
|
||||||
|
|
||||||
// we remove 4 bytes to get the message size out of the IPC command
|
// we don't care about the error value as we will reset the
|
||||||
// size
|
// connection after that anyways
|
||||||
SocketIPC::IPCBuffer res = ParseCommand(&m_ipc_buffer[4], m_ret_buffer, (u32)receive_length - 4);
|
if (write_portable(m_msgsock, res.buffer, res.size) < 0)
|
||||||
|
{
|
||||||
// we don't care about the error value as we will reset the
|
|
||||||
// connection after that anyways
|
|
||||||
if (write_portable(m_msgsock, res.buffer, res.size) < 0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close_portable(m_msgsock);
|
close_portable(m_msgsock);
|
||||||
|
@ -244,20 +251,6 @@ SocketIPC::~SocketIPC()
|
||||||
DESTRUCTOR_CATCHALL
|
DESTRUCTOR_CATCHALL
|
||||||
}
|
}
|
||||||
|
|
||||||
char* SocketIPC::MakeOkIPC(char* ret_buffer, uint32_t size = 5)
|
|
||||||
{
|
|
||||||
ToArray<uint32_t>(ret_buffer, size, 0);
|
|
||||||
ret_buffer[4] = IPC_OK;
|
|
||||||
return ret_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* SocketIPC::MakeFailIPC(char* ret_buffer, uint32_t size = 5)
|
|
||||||
{
|
|
||||||
ToArray<uint32_t>(ret_buffer, size, 0);
|
|
||||||
ret_buffer[4] = IPC_FAIL;
|
|
||||||
return ret_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketIPC::IPCBuffer SocketIPC::ParseCommand(char* buf, char* ret_buffer, u32 buf_size)
|
SocketIPC::IPCBuffer SocketIPC::ParseCommand(char* buf, char* ret_buffer, u32 buf_size)
|
||||||
{
|
{
|
||||||
// currently all our instructions require a running VM so we check once
|
// currently all our instructions require a running VM so we check once
|
||||||
|
@ -278,7 +271,7 @@ SocketIPC::IPCBuffer SocketIPC::ParseCommand(char* buf, char* ret_buffer, u32 bu
|
||||||
// YY YY YY YY from schema below
|
// YY YY YY YY from schema below
|
||||||
// curently always used by implemented commands so it is out of the
|
// curently always used by implemented commands so it is out of the
|
||||||
// loop
|
// loop
|
||||||
u32 a = FromArray<u32>(&buf[buf_cnt], 1);
|
const u32 a = FromArray<u32>(&buf[buf_cnt], 1);
|
||||||
|
|
||||||
// IPC Message event (1 byte)
|
// IPC Message event (1 byte)
|
||||||
// | Memory address (4 byte)
|
// | Memory address (4 byte)
|
||||||
|
@ -295,8 +288,7 @@ SocketIPC::IPCBuffer SocketIPC::ParseCommand(char* buf, char* ret_buffer, u32 bu
|
||||||
{
|
{
|
||||||
if (!SafetyChecks(buf_cnt, 5, ret_cnt, 1, buf_size))
|
if (!SafetyChecks(buf_cnt, 5, ret_cnt, 1, buf_size))
|
||||||
goto error;
|
goto error;
|
||||||
u8 res;
|
const u8 res = memRead8(a);
|
||||||
res = memRead8(a);
|
|
||||||
ToArray(ret_buffer, res, ret_cnt);
|
ToArray(ret_buffer, res, ret_cnt);
|
||||||
ret_cnt += 1;
|
ret_cnt += 1;
|
||||||
buf_cnt += 5;
|
buf_cnt += 5;
|
||||||
|
@ -306,8 +298,7 @@ SocketIPC::IPCBuffer SocketIPC::ParseCommand(char* buf, char* ret_buffer, u32 bu
|
||||||
{
|
{
|
||||||
if (!SafetyChecks(buf_cnt, 5, ret_cnt, 2, buf_size))
|
if (!SafetyChecks(buf_cnt, 5, ret_cnt, 2, buf_size))
|
||||||
goto error;
|
goto error;
|
||||||
u16 res;
|
const u16 res = memRead16(a);
|
||||||
res = memRead16(a);
|
|
||||||
ToArray(ret_buffer, res, ret_cnt);
|
ToArray(ret_buffer, res, ret_cnt);
|
||||||
ret_cnt += 2;
|
ret_cnt += 2;
|
||||||
buf_cnt += 5;
|
buf_cnt += 5;
|
||||||
|
@ -317,8 +308,7 @@ SocketIPC::IPCBuffer SocketIPC::ParseCommand(char* buf, char* ret_buffer, u32 bu
|
||||||
{
|
{
|
||||||
if (!SafetyChecks(buf_cnt, 5, ret_cnt, 4, buf_size))
|
if (!SafetyChecks(buf_cnt, 5, ret_cnt, 4, buf_size))
|
||||||
goto error;
|
goto error;
|
||||||
u32 res;
|
const u32 res = memRead32(a);
|
||||||
res = memRead32(a);
|
|
||||||
ToArray(ret_buffer, res, ret_cnt);
|
ToArray(ret_buffer, res, ret_cnt);
|
||||||
ret_cnt += 4;
|
ret_cnt += 4;
|
||||||
buf_cnt += 5;
|
buf_cnt += 5;
|
||||||
|
@ -328,7 +318,7 @@ SocketIPC::IPCBuffer SocketIPC::ParseCommand(char* buf, char* ret_buffer, u32 bu
|
||||||
{
|
{
|
||||||
if (!SafetyChecks(buf_cnt, 5, ret_cnt, 8, buf_size))
|
if (!SafetyChecks(buf_cnt, 5, ret_cnt, 8, buf_size))
|
||||||
goto error;
|
goto error;
|
||||||
u64 res;
|
u64 res = 0;
|
||||||
memRead64(a, &res);
|
memRead64(a, &res);
|
||||||
ToArray(ret_buffer, res, ret_cnt);
|
ToArray(ret_buffer, res, ret_cnt);
|
||||||
ret_cnt += 8;
|
ret_cnt += 8;
|
||||||
|
|
109
pcsx2/IPC.h
109
pcsx2/IPC.h
|
@ -47,36 +47,36 @@ protected:
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum memory used by an IPC message request.
|
* Maximum memory used by an IPC message request.
|
||||||
* Equivalent to 50,000 Write64 requests.
|
* Equivalent to 50,000 Write64 requests.
|
||||||
*/
|
*/
|
||||||
#define MAX_IPC_SIZE 650000
|
#define MAX_IPC_SIZE 650000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum memory used by an IPC message reply.
|
* Maximum memory used by an IPC message reply.
|
||||||
* Equivalent to 50,000 Read64 replies.
|
* Equivalent to 50,000 Read64 replies.
|
||||||
*/
|
*/
|
||||||
#define MAX_IPC_RETURN_SIZE 450000
|
#define MAX_IPC_RETURN_SIZE 450000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPC return buffer.
|
* IPC return buffer.
|
||||||
* A preallocated buffer used to store all IPC replies.
|
* A preallocated buffer used to store all IPC replies.
|
||||||
* to the size of 50.000 MsgWrite64 IPC calls.
|
* to the size of 50.000 MsgWrite64 IPC calls.
|
||||||
*/
|
*/
|
||||||
char* m_ret_buffer;
|
char* m_ret_buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPC messages buffer.
|
* IPC messages buffer.
|
||||||
* A preallocated buffer used to store all IPC messages.
|
* A preallocated buffer used to store all IPC messages.
|
||||||
*/
|
*/
|
||||||
char* m_ipc_buffer;
|
char* m_ipc_buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPC Command messages opcodes.
|
* IPC Command messages opcodes.
|
||||||
* A list of possible operations possible by the IPC.
|
* A list of possible operations possible by the IPC.
|
||||||
* Each one of them is what we call an "opcode" and is the first
|
* Each one of them is what we call an "opcode" and is the first
|
||||||
* byte sent by the IPC to differentiate between commands.
|
* byte sent by the IPC to differentiate between commands.
|
||||||
*/
|
*/
|
||||||
enum IPCCommand : unsigned char
|
enum IPCCommand : unsigned char
|
||||||
{
|
{
|
||||||
MsgRead8 = 0, /**< Read 8 bit value to memory. */
|
MsgRead8 = 0, /**< Read 8 bit value to memory. */
|
||||||
|
@ -92,9 +92,9 @@ protected:
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPC message buffer.
|
* IPC message buffer.
|
||||||
* A list of all needed fields to store an IPC message.
|
* A list of all needed fields to store an IPC message.
|
||||||
*/
|
*/
|
||||||
struct IPCBuffer
|
struct IPCBuffer
|
||||||
{
|
{
|
||||||
int size; /**< Size of the buffer. */
|
int size; /**< Size of the buffer. */
|
||||||
|
@ -102,11 +102,11 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPC result codes.
|
* IPC result codes.
|
||||||
* A list of possible result codes the IPC can send back.
|
* A list of possible result codes the IPC can send back.
|
||||||
* Each one of them is what we call an "opcode" or "tag" and is the
|
* Each one of them is what we call an "opcode" or "tag" and is the
|
||||||
* first byte sent by the IPC to differentiate between results.
|
* first byte sent by the IPC to differentiate between results.
|
||||||
*/
|
*/
|
||||||
enum IPCResult : unsigned char
|
enum IPCResult : unsigned char
|
||||||
{
|
{
|
||||||
IPC_OK = 0, /**< IPC command successfully completed. */
|
IPC_OK = 0, /**< IPC command successfully completed. */
|
||||||
|
@ -119,28 +119,33 @@ protected:
|
||||||
// Thread used to relay IPC commands.
|
// Thread used to relay IPC commands.
|
||||||
void ExecuteTaskInThread();
|
void ExecuteTaskInThread();
|
||||||
|
|
||||||
/* Internal function, Parses an IPC command.
|
/**
|
||||||
* buf: buffer containing the IPC command.
|
* Internal function, Parses an IPC command.
|
||||||
* buf_size: size of the buffer announced.
|
* buf: buffer containing the IPC command.
|
||||||
* ret_buffer: buffer that will be used to send the reply.
|
* buf_size: size of the buffer announced.
|
||||||
* return value: IPCBuffer containing a buffer with the result
|
* ret_buffer: buffer that will be used to send the reply.
|
||||||
* of the command and its size. */
|
* return value: IPCBuffer containing a buffer with the result
|
||||||
|
* of the command and its size.
|
||||||
|
*/
|
||||||
IPCBuffer ParseCommand(char* buf, char* ret_buffer, u32 buf_size);
|
IPCBuffer ParseCommand(char* buf, char* ret_buffer, u32 buf_size);
|
||||||
|
|
||||||
/* Formats an IPC buffer
|
/**
|
||||||
* ret_buffer: return buffer to use.
|
* Formats an IPC buffer
|
||||||
* size: size of the IPC buffer.
|
* ret_buffer: return buffer to use.
|
||||||
* return value: buffer containing the status code allocated of size
|
* size: size of the IPC buffer.
|
||||||
* size */
|
* return value: buffer containing the status code allocated of size
|
||||||
|
*/
|
||||||
static inline char* MakeOkIPC(char* ret_buffer, uint32_t size);
|
static inline char* MakeOkIPC(char* ret_buffer, uint32_t size);
|
||||||
static inline char* MakeFailIPC(char* ret_buffer, uint32_t size);
|
static inline char* MakeFailIPC(char* ret_buffer, uint32_t size);
|
||||||
|
|
||||||
/* Converts an uint to an char* in little endian
|
/**
|
||||||
* res_array: the array to modify
|
* Converts an uint to an char* in little endian
|
||||||
* res: the value to convert
|
* res_array: the array to modify
|
||||||
* i: when to insert it into the array
|
* res: the value to convert
|
||||||
* return value: res_array
|
* i: when to insert it into the array
|
||||||
* NB: implicitely inlined */
|
* return value: res_array
|
||||||
|
* NB: implicitely inlined
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static char* ToArray(char* res_array, T res, int i)
|
static char* ToArray(char* res_array, T res, int i)
|
||||||
{
|
{
|
||||||
|
@ -148,11 +153,13 @@ protected:
|
||||||
return res_array;
|
return res_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converts a char* to an uint in little endian
|
/**
|
||||||
* arr: the array to convert
|
* Converts a char* to an uint in little endian
|
||||||
* i: when to load it from the array
|
* arr: the array to convert
|
||||||
* return value: the converted value
|
* i: when to load it from the array
|
||||||
* NB: implicitely inlined */
|
* return value: the converted value
|
||||||
|
* NB: implicitely inlined
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static T FromArray(char* arr, int i)
|
static T FromArray(char* arr, int i)
|
||||||
{
|
{
|
||||||
|
@ -160,9 +167,9 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures an IPC message isn't too big.
|
* Ensures an IPC message isn't too big.
|
||||||
* return value: false if checks failed, true otherwise.
|
* return value: false if checks failed, true otherwise.
|
||||||
*/
|
*/
|
||||||
static inline bool SafetyChecks(u32 command_len, int command_size, u32 reply_len, int reply_size = 0, u32 buf_size = MAX_IPC_SIZE - 1)
|
static inline bool SafetyChecks(u32 command_len, int command_size, u32 reply_len, int reply_size = 0, u32 buf_size = MAX_IPC_SIZE - 1)
|
||||||
{
|
{
|
||||||
bool res = ((command_len + command_size) > buf_size ||
|
bool res = ((command_len + command_size) > buf_size ||
|
||||||
|
|
|
@ -244,7 +244,7 @@ void SysCoreThread::GameStartingInThread()
|
||||||
#ifdef USE_SAVESLOT_UI_UPDATES
|
#ifdef USE_SAVESLOT_UI_UPDATES
|
||||||
UI_UpdateSysControls();
|
UI_UpdateSysControls();
|
||||||
#endif
|
#endif
|
||||||
if(EmuConfig.EnableIPC && m_IpcState == OFF)
|
if (EmuConfig.EnableIPC && m_IpcState == OFF)
|
||||||
{
|
{
|
||||||
m_IpcState = ON;
|
m_IpcState = ON;
|
||||||
m_socketIpc = std::make_unique<SocketIPC>(this);
|
m_socketIpc = std::make_unique<SocketIPC>(this);
|
||||||
|
|
Loading…
Reference in New Issue