From 1a1b5bdb385a06ece43d23393d6eeab5fc7bdf4b Mon Sep 17 00:00:00 2001 From: Jan Vidar Krey Date: Sat, 21 Mar 2009 02:58:53 +0100 Subject: [PATCH] Fixed nasty crash if a user sends a very large command to the hub. Will overwrite heap memory. Thanks to Toast who found this bug. Signed-off-by: Jan Vidar Krey --- src/netevent.c | 88 ++++++++++++++++++++++++++++++-------------------- src/user.h | 11 ++++--- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/src/netevent.c b/src/netevent.c index d0f2b83..6f116ed 100644 --- a/src/netevent.c +++ b/src/netevent.c @@ -25,10 +25,9 @@ void net_on_read(int fd, short ev, void *arg) static char buf[MAX_RECV_BUF]; struct user* user = (struct user*) arg; char* pos; - char* start; - ssize_t offset; + size_t offset; + size_t buflen; ssize_t size; - ssize_t buflen; int more = 1; int flag_close = 0; @@ -55,11 +54,7 @@ void net_on_read(int fd, short ev, void *arg) memcpy(buf, user->recv_buf, user->recv_buf_offset); offset = user->recv_buf_offset; } - else - { - offset = 0; - } - + size = net_recv(fd, &buf[offset], MAX_RECV_BUF - offset, 0); if (size == -1) { @@ -75,40 +70,63 @@ void net_on_read(int fd, short ev, void *arg) else { buflen = offset + size; - start = buf; - while ((pos = strchr(start, '\n'))) + ssize_t handled = 0; + + while ((pos = memchr(&buf[handled], '\n', (buflen - handled)))) { pos[0] = '\0'; - if (*start && strlen(start) < user->hub->config->max_recv_buffer) - { - if (hub_handle_message(user, start, &pos[0]-&start[0]) == -1) - { - flag_close = quit_protocol_error; - more = 0; - break; - } - } - start = &pos[1]; - } - - if (!more) break; - - if (&buf[offset + size] > &start[0]) - { - if (!user->recv_buf) - { - user->recv_buf = hub_malloc(user->hub->config->max_recv_buffer); - } + size_t msglen = &pos[0] - &buf[handled]; - if (!user->recv_buf) + if (user_flag_get(user, flag_maxbuf)) { - flag_close = quit_memory_error; - break; + user_flag_unset(user, flag_maxbuf); } else { - memcpy(user->recv_buf, start, &buf[offset + size] - &start[0]); - user->recv_buf_offset = &buf[offset + size] - &start[0]; + if (msglen < user->hub->config->max_recv_buffer) + { + if (hub_handle_message(user, &buf[handled], msglen) == -1) + { + flag_close = quit_protocol_error; + more = 0; + break; + } + } + } + handled += msglen; + handled++; + } + + if (handled == 0 && user_flag_get(user, flag_maxbuf)) + handled = buflen; + + if (!more) + break; + + if (handled < buflen) + { + if ((buflen - handled) > user->hub->config->max_recv_buffer) + { + user_flag_set(user, flag_maxbuf); + hub_free(user->recv_buf); + user->recv_buf = 0; + user->recv_buf_offset = 0; + } + else + { + if (!user->recv_buf) + user->recv_buf = hub_malloc(user->hub->config->max_recv_buffer); + + if (user->recv_buf) + { + memcpy(user->recv_buf, &buf[handled], buflen - handled); + user->recv_buf_offset = buflen - handled; + } + else + { + flag_close = quit_memory_error; + break; + } } } else diff --git a/src/user.h b/src/user.h index f12c7bc..1c97185 100644 --- a/src/user.h +++ b/src/user.h @@ -47,11 +47,12 @@ enum user_flags feature_ping = 0x00000080, /** PING: Hub pinger information extension */ feature_link = 0x00000100, /** LINK: Hub link (not supported) */ flag_ignore = 0x01000000, /** Ignore further reads */ - flag_choke = 0x02000000, /** Choked: Cannot send, waiting for write event */ - flag_want_read = 0x04000000, /** Need to read (SSL) */ - flag_want_write = 0x08000000, /** Need to write (SSL) */ - flag_user_list = 0x10000000, /** Send queue bypass (when receiving the send queue) */ - flag_nat = 0x20000000, /** nat override enabled */ + flag_maxbuf = 0x02000000, /** Hit max buf read, ignore msg */ + flag_choke = 0x04000000, /** Choked: Cannot send, waiting for write event */ + flag_want_read = 0x08000000, /** Need to read (SSL) */ + flag_want_write = 0x10000000, /** Need to write (SSL) */ + flag_user_list = 0x20000000, /** Send queue bypass (when receiving the send queue) */ + flag_nat = 0x40000000, /** nat override enabled */ };