mirror of
https://github.com/weechat/weechat.git
synced 2026-06-12 14:14:48 +02:00
irc: limit size of data received from the server to prevent memory exhaustion
A malicious or compromised IRC server could send data with no end-of-line (or a flood of "005" messages), making WeeChat accumulate it in a buffer that grew without limit, until all memory was exhausted. The unterminated received message and the accumulated "005" (ISUPPORT) data are now bounded by IRC_SERVER_RECV_MSG_MAX_LENGTH and IRC_SERVER_ISUPPORT_MAX_LENGTH: extra data is ignored once the limit is reached.
This commit is contained in:
@@ -22,6 +22,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
- core: fix option weechat.look.color_real_white not applied when color is "white" on 16+ colors terminals ([#1742](https://github.com/weechat/weechat/issues/1742))
|
- core: fix option weechat.look.color_real_white not applied when color is "white" on 16+ colors terminals ([#1742](https://github.com/weechat/weechat/issues/1742))
|
||||||
- irc: fix tag in message with list of names when joining a channel
|
- irc: fix tag in message with list of names when joining a channel
|
||||||
- fset: remove error displayed in core buffer when clicking with the mouse below the last option displayed
|
- fset: remove error displayed in core buffer when clicking with the mouse below the last option displayed
|
||||||
|
- irc: limit size of data received from the server to prevent memory exhaustion
|
||||||
- relay: limit size of decompressed websocket frame with permessage-deflate to prevent memory exhaustion ([GHSA-v2v4-45wm-5cr3](https://github.com/weechat/weechat/security/advisories/GHSA-v2v4-45wm-5cr3))
|
- relay: limit size of decompressed websocket frame with permessage-deflate to prevent memory exhaustion ([GHSA-v2v4-45wm-5cr3](https://github.com/weechat/weechat/security/advisories/GHSA-v2v4-45wm-5cr3))
|
||||||
- relay: fix timing attack on password authentication ([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc))
|
- relay: fix timing attack on password authentication ([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc))
|
||||||
- api, relay: fix timing attack on TOTP validation ([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc))
|
- api, relay: fix timing attack on TOTP validation ([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc))
|
||||||
|
|||||||
@@ -4164,16 +4164,25 @@ IRC_PROTOCOL_CALLBACK(005)
|
|||||||
if (ctxt->server->isupport)
|
if (ctxt->server->isupport)
|
||||||
{
|
{
|
||||||
length_isupport = strlen (ctxt->server->isupport);
|
length_isupport = strlen (ctxt->server->isupport);
|
||||||
isupport2 = realloc (ctxt->server->isupport,
|
/*
|
||||||
length_isupport + /* existing */
|
* limit the size of the accumulated ISUPPORT data: once the
|
||||||
1 + /* space */
|
* maximum is reached, ignore the extra data (protection against a
|
||||||
length + /* new */
|
* server flooding "005" messages, which would consume all the
|
||||||
1);
|
* memory)
|
||||||
if (isupport2)
|
*/
|
||||||
|
if (length_isupport + 1 + length < IRC_SERVER_ISUPPORT_MAX_LENGTH)
|
||||||
{
|
{
|
||||||
ctxt->server->isupport = isupport2;
|
isupport2 = realloc (ctxt->server->isupport,
|
||||||
strcat (ctxt->server->isupport, " ");
|
length_isupport + /* existing */
|
||||||
strcat (ctxt->server->isupport, str_info);
|
1 + /* space */
|
||||||
|
length + /* new */
|
||||||
|
1);
|
||||||
|
if (isupport2)
|
||||||
|
{
|
||||||
|
ctxt->server->isupport = isupport2;
|
||||||
|
strcat (ctxt->server->isupport, " ");
|
||||||
|
strcat (ctxt->server->isupport, str_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -3409,6 +3409,14 @@ irc_server_msgq_add_unterminated (struct t_irc_server *server,
|
|||||||
|
|
||||||
if (server->unterminated_message)
|
if (server->unterminated_message)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* limit the size of the unterminated message: once the maximum is
|
||||||
|
* reached, ignore the extra data (protection against a server sending
|
||||||
|
* a very long line without end-of-line, which would consume all the
|
||||||
|
* memory)
|
||||||
|
*/
|
||||||
|
if (strlen (server->unterminated_message) >= IRC_SERVER_RECV_MSG_MAX_LENGTH)
|
||||||
|
return;
|
||||||
unterminated_message2 =
|
unterminated_message2 =
|
||||||
realloc (server->unterminated_message,
|
realloc (server->unterminated_message,
|
||||||
(strlen (server->unterminated_message) +
|
(strlen (server->unterminated_message) +
|
||||||
|
|||||||
@@ -144,6 +144,15 @@ enum t_irc_server_option
|
|||||||
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_BYTES 4096
|
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_BYTES 4096
|
||||||
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_LINES 24
|
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_LINES 24
|
||||||
|
|
||||||
|
/*
|
||||||
|
* maximum length of an unterminated message (a received line without
|
||||||
|
* end-of-line) and of the accumulated "005" (ISUPPORT) data; these limits
|
||||||
|
* protect against a server sending a huge amount of data without end-of-line
|
||||||
|
* (or a flood of "005" messages), which would consume all the memory
|
||||||
|
*/
|
||||||
|
#define IRC_SERVER_RECV_MSG_MAX_LENGTH (64 * 1024)
|
||||||
|
#define IRC_SERVER_ISUPPORT_MAX_LENGTH (64 * 1024)
|
||||||
|
|
||||||
/* casemapping (string comparisons for nicks/channels) */
|
/* casemapping (string comparisons for nicks/channels) */
|
||||||
enum t_irc_server_casemapping
|
enum t_irc_server_casemapping
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3866,6 +3866,44 @@ TEST(IrcProtocolWithServer, 005_full)
|
|||||||
STRCMP_EQUAL(IRC_MSG_005 " " IRC_MSG_005, ptr_server->isupport);
|
STRCMP_EQUAL(IRC_MSG_005 " " IRC_MSG_005, ptr_server->isupport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test functions:
|
||||||
|
* irc_protocol_cb_005 (accumulated ISUPPORT is bounded)
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST(IrcProtocolWithServer, 005_limit)
|
||||||
|
{
|
||||||
|
char str_msg[4096], str_value[3500];
|
||||||
|
size_t length1, length2;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
SRV_INIT;
|
||||||
|
|
||||||
|
memset (str_value, 'X', sizeof (str_value) - 1);
|
||||||
|
str_value[sizeof (str_value) - 1] = '\0';
|
||||||
|
snprintf (str_msg, sizeof (str_msg),
|
||||||
|
":server 005 alice TEST=%s :are supported", str_value);
|
||||||
|
|
||||||
|
/* flood the server with "005" messages */
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
server_recv (str_msg);
|
||||||
|
}
|
||||||
|
CHECK(ptr_server->isupport);
|
||||||
|
length1 = strlen (ptr_server->isupport);
|
||||||
|
|
||||||
|
/* the accumulated ISUPPORT data must be bounded */
|
||||||
|
CHECK(length1 <= IRC_SERVER_ISUPPORT_MAX_LENGTH + sizeof (str_value));
|
||||||
|
|
||||||
|
/* receiving more "005" messages must not grow it any further */
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
server_recv (str_msg);
|
||||||
|
}
|
||||||
|
length2 = strlen (ptr_server->isupport);
|
||||||
|
LONGS_EQUAL(length1, length2);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test functions:
|
* Test functions:
|
||||||
* irc_protocol_cb_005 (infos from server, multiple messages)
|
* irc_protocol_cb_005 (infos from server, multiple messages)
|
||||||
|
|||||||
@@ -65,6 +65,49 @@ TEST(IrcServer, Valid)
|
|||||||
irc_server_free (server);
|
irc_server_free (server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test functions:
|
||||||
|
* irc_server_msgq_add_unterminated (via irc_server_msgq_add_buffer)
|
||||||
|
*
|
||||||
|
* Check that data received without any end-of-line does not grow the
|
||||||
|
* unterminated message buffer without limit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST(IrcServer, MsgqAddBufferLimit)
|
||||||
|
{
|
||||||
|
struct t_irc_server *server;
|
||||||
|
char chunk[4097];
|
||||||
|
int i;
|
||||||
|
size_t length1, length2;
|
||||||
|
|
||||||
|
server = irc_server_alloc ("server_msgq");
|
||||||
|
CHECK(server);
|
||||||
|
|
||||||
|
memset (chunk, 'a', sizeof (chunk) - 1);
|
||||||
|
chunk[sizeof (chunk) - 1] = '\0';
|
||||||
|
|
||||||
|
/* feed a lot of data with no end-of-line */
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
irc_server_msgq_add_buffer (server, chunk);
|
||||||
|
}
|
||||||
|
CHECK(server->unterminated_message);
|
||||||
|
length1 = strlen (server->unterminated_message);
|
||||||
|
|
||||||
|
/* the buffer must be bounded (not ~400 KB) */
|
||||||
|
CHECK(length1 <= IRC_SERVER_RECV_MSG_MAX_LENGTH + sizeof (chunk));
|
||||||
|
|
||||||
|
/* feeding more data must not grow the buffer any further */
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
irc_server_msgq_add_buffer (server, chunk);
|
||||||
|
}
|
||||||
|
length2 = strlen (server->unterminated_message);
|
||||||
|
LONGS_EQUAL(length1, length2);
|
||||||
|
|
||||||
|
irc_server_free (server);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test functions:
|
* Test functions:
|
||||||
* irc_server_search
|
* irc_server_search
|
||||||
|
|||||||
Reference in New Issue
Block a user