Skip to content

Instantly share code, notes, and snippets.

@slingamn
Last active August 31, 2017 17:39
Show Gist options
  • Save slingamn/28b6e5658c48ead403d903fb3d29dce3 to your computer and use it in GitHub Desktop.
Save slingamn/28b6e5658c48ead403d903fb3d29dce3 to your computer and use it in GitHub Desktop.
commit 01b54d12a38e050d5563dd6fe199eaafe9534680
Author: Shivaram Lingamneni <slingamn@cs.stanford.edu>
Date: Thu Aug 31 13:33:18 2017 -0400
fixes to irc buffer handling
* #12562: consume all available SSL data before returning to event loop
* use a constant-sized read buffer to prevent a DoS attack
diff --git a/libpurple/protocols/irc/irc.c b/libpurple/protocols/irc/irc.c
index f101cbe..c3edfa1 100644
--- a/libpurple/protocols/irc/irc.c
+++ b/libpurple/protocols/irc/irc.c
@@ -346,6 +346,7 @@ static void irc_login(PurpleAccount *account)
gc->proto_data = irc = g_new0(struct irc_conn, 1);
irc->fd = -1;
irc->account = account;
+ irc->inbuf = g_malloc(IRC_BUFSIZE);
irc->outbuf = purple_circ_buffer_new(512);
userparts = g_strsplit(username, "@", 2);
@@ -674,6 +675,7 @@ static void irc_input_cb_ssl(gpointer data, PurpleSslConnection *gsc,
PurpleConnection *gc = data;
struct irc_conn *irc = gc->proto_data;
+ int read_len;
int len;
if(!g_list_find(purple_connections_get_all(), gc)) {
@@ -681,45 +683,57 @@ static void irc_input_cb_ssl(gpointer data, PurpleSslConnection *gsc,
return;
}
- if (irc->inbuflen < irc->inbufused + IRC_INITIAL_BUFSIZE) {
- irc->inbuflen += IRC_INITIAL_BUFSIZE;
- irc->inbuf = g_realloc(irc->inbuf, irc->inbuflen);
- }
+ while (1) {
+ /* IRC messages are at most 1024 bytes; if the buffer is full
+ of "leftover" data that hasn't been parsed into a complete
+ IRC message, it's the server's fault. */
+ read_len = (IRC_BUFSIZE - irc->inbufused) - 1;
+ if (read_len < 1) {
+ purple_connection_error_reason (gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Invalid response from server"));
+ return;
+ }
+ len = purple_ssl_read(gsc, irc->inbuf + irc->inbufused, read_len);
- len = purple_ssl_read(gsc, irc->inbuf + irc->inbufused, IRC_INITIAL_BUFSIZE - 1);
+ if (len < 0 && errno == EAGAIN) {
+ /* Try again later */
+ return;
+ } else if (len < 0) {
+ gchar *tmp = g_strdup_printf(_("Lost connection with server: %s"),
+ g_strerror(errno));
+ purple_connection_error_reason (gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
+ g_free(tmp);
+ return;
+ } else if (len == 0) {
+ purple_connection_error_reason (gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Server closed the connection"));
+ return;
+ }
- if (len < 0 && errno == EAGAIN) {
- /* Try again later */
- return;
- } else if (len < 0) {
- gchar *tmp = g_strdup_printf(_("Lost connection with server: %s"),
- g_strerror(errno));
- purple_connection_error_reason (gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
- g_free(tmp);
- return;
- } else if (len == 0) {
- purple_connection_error_reason (gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Server closed the connection"));
- return;
+ read_input(irc, len);
}
-
- read_input(irc, len);
}
static void irc_input_cb(gpointer data, gint source, PurpleInputCondition cond)
{
PurpleConnection *gc = data;
struct irc_conn *irc = gc->proto_data;
+ int read_len;
int len;
- if (irc->inbuflen < irc->inbufused + IRC_INITIAL_BUFSIZE) {
- irc->inbuflen += IRC_INITIAL_BUFSIZE;
- irc->inbuf = g_realloc(irc->inbuf, irc->inbuflen);
+ read_len = (IRC_BUFSIZE - irc->inbufused) - 1;
+ /* see irc_input_cb_ssl */
+ if (read_len < 1) {
+ purple_connection_error_reason (gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Invalid response from server"));
+ return;
}
- len = read(irc->fd, irc->inbuf + irc->inbufused, IRC_INITIAL_BUFSIZE - 1);
+ len = read(irc->fd, irc->inbuf + irc->inbufused, read_len);
if (len < 0 && errno == EAGAIN) {
return;
} else if (len < 0) {
diff --git a/libpurple/protocols/irc/irc.h b/libpurple/protocols/irc/irc.h
index 7e74ae8..25ac550 100644
--- a/libpurple/protocols/irc/irc.h
+++ b/libpurple/protocols/irc/irc.h
@@ -44,7 +44,8 @@
#define IRC_DEFAULT_QUIT "Leaving."
-#define IRC_INITIAL_BUFSIZE 1024
+/* IRCv3 maximum message length is half this */
+#define IRC_BUFSIZE 2048
#define IRC_MAX_MSG_SIZE 512
import socket, os, fcntl, logging, select
serversocket = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(('127.0.0.1', 7777))
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversocket.listen(5)
while 1:
(clientsocket, address) = serversocket.accept()
fcntl.fcntl(clientsocket, fcntl.F_SETFL, os.O_NONBLOCK)
sl = [clientsocket]
while 1:
r, w, e = select.select(sl, sl, sl)
try:
if r:
clientsocket.recv(1024)
if w:
clientsocket.send('\1' * 1024)
except socket.error as e:
logging.exception(e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment