Permalink
Browse files

Issue 102: Piping null to the server will crash it

  • Loading branch information...
1 parent 0731dc8 commit 75cc83685e103bc8ba380a57468c8f04413033f9 Trond Norbye committed with dustin Oct 28, 2009
Showing with 46 additions and 2 deletions.
  1. +29 −2 memcached.c
  2. +17 −0 testapp.c
View
@@ -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)
View
@@ -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 },

0 comments on commit 75cc836

Please sign in to comment.