From 75cc83685e103bc8ba380a57468c8f04413033f9 Mon Sep 17 00:00:00 2001 From: Trond Norbye Date: Wed, 28 Oct 2009 11:51:05 +0100 Subject: [PATCH] Issue 102: Piping null to the server will crash it --- memcached.c | 31 +++++++++++++++++++++++++++++-- testapp.c | 17 +++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/memcached.c b/memcached.c index f6f0071..1789135 100644 --- a/memcached.c +++ b/memcached.c @@ -3127,9 +3127,27 @@ static int try_read_command(conn *c) { if (c->rbytes == 0) return 0; + el = memchr(c->rcurr, '\n', c->rbytes); - if (!el) + if (!el) { + if (c->rbytes > 1024) { + /* + * We didn't have a '\n' in the first k. This _has_ to be a + * large multiget, if not we should just nuke the connection. + */ + char *ptr = c->rcurr; + while (*ptr == ' ') { /* ignore leading whitespaces */ + ++ptr; + } + + if (strcmp(ptr, "get ") && strcmp(ptr, "gets ")) { + conn_set_state(c, conn_closing); + return 1; + } + } + return 0; + } cont = el + 1; if ((el - c->rcurr) > 1 && *(el - 1) == '\r') { el--; @@ -3191,12 +3209,17 @@ static enum try_read_result try_read_udp(conn *c) { * close. * before reading, move the remaining incomplete fragment of a command * (if any) to the beginning of the buffer. + * + * To protect us from someone flooding a connection with bogus data causing + * the connection to eat up all available memory, break out and start looking + * at the data I've got after a number of reallocs... + * * @return enum try_read_result */ static enum try_read_result try_read_network(conn *c) { enum try_read_result gotdata = READ_NO_DATA_RECEIVED; int res; - + int num_allocs = 0; assert(c != NULL); if (c->rcurr != c->rbuf) { @@ -3207,6 +3230,10 @@ static enum try_read_result try_read_network(conn *c) { while (1) { if (c->rbytes >= c->rsize) { + if (num_allocs == 4) { + return gotdata; + } + ++num_allocs; char *new_rbuf = realloc(c->rbuf, c->rsize * 2); if (!new_rbuf) { if (settings.verbose > 0) diff --git a/testapp.c b/testapp.c index b0491c3..5ff2a1f 100644 --- a/testapp.c +++ b/testapp.c @@ -538,6 +538,22 @@ static enum test_return test_issue_92(void) { return TEST_PASS; } +static enum test_return test_issue_102(void) { + char buffer[4096]; + memset(buffer, ' ', sizeof(buffer)); + buffer[sizeof(buffer) - 1] = '\0'; + + close(sock); + sock = connect_server("127.0.0.1", port, false); + + send_ascii_command(buffer); + /* verify that the server closed the connection */ + assert(read(sock, buffer, sizeof(buffer)) == 0); + close(sock); + sock = connect_server("127.0.0.1", port, false); + return TEST_PASS; +} + static enum test_return start_memcached_server(void) { server_pid = start_server(&port, false, 600); sock = connect_server("127.0.0.1", port, false); @@ -1676,6 +1692,7 @@ struct testcase testcases[] = { /* The following tests all run towards the same server */ { "start_server", start_memcached_server }, { "issue_92", test_issue_92 }, + { "issue_102", test_issue_102 }, { "binary_noop", test_binary_noop }, { "binary_quit", test_binary_quit }, { "binary_quitq", test_binary_quitq }, -- 1.6.5.3