From f3429dac1bca62e4b06ee33071c349533a378421 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Wed, 24 Sep 2014 11:13:33 +0100 Subject: [PATCH] Fix for double free if incorrect password is passed --- server/modules/include/maxscaled.h | 6 ++++-- server/modules/protocol/maxscaled.c | 25 +++++++++++++++---------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/server/modules/include/maxscaled.h b/server/modules/include/maxscaled.h index 3733772d8..fd4e6439e 100644 --- a/server/modules/include/maxscaled.h +++ b/server/modules/include/maxscaled.h @@ -30,13 +30,15 @@ * @endverbatim */ #include +#include /** * The telnetd specific protocol structure to put in the DCB. */ typedef struct maxscaled { - int state; /**< The connection state */ - char *username; /**< The login name of the user */ + SPINLOCK lock; /**< Protocol structure lock */ + int state; /**< The connection state */ + char *username; /**< The login name of the user */ } MAXSCALED; #define MAXSCALED_STATE_LOGIN 1 /**< Issued login prompt */ diff --git a/server/modules/protocol/maxscaled.c b/server/modules/protocol/maxscaled.c index 1ece013f9..268b33b52 100644 --- a/server/modules/protocol/maxscaled.c +++ b/server/modules/protocol/maxscaled.c @@ -166,7 +166,6 @@ char *password; { dcb_printf(dcb, "FAILED"); maxscaled->state = MAXSCALED_STATE_LOGIN; - free(maxscaled->username); } gwbuf_consume(head, GWBUF_LENGTH(head)); free(password); @@ -276,17 +275,18 @@ int n_connect = 0; client_dcb->fd = so; client_dcb->remote = strdup(inet_ntoa(addr.sin_addr)); memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL)); - client_dcb->session = - session_alloc(dcb->session->service, client_dcb); - maxscaled_pr = (MAXSCALED *)malloc(sizeof(MAXSCALED)); - maxscaled_pr->username = NULL; - client_dcb->protocol = (void *)maxscaled_pr; - - if (maxscaled_pr == NULL) - { + if ((maxscaled_pr = (MAXSCALED *)malloc(sizeof(MAXSCALED))) == NULL) + { + client_dcb->protocol = NULL; dcb_add_to_zombieslist(client_dcb); return n_connect; } + maxscaled_pr->username = NULL; + spinlock_init(&maxscaled_pr->lock); + client_dcb->protocol = (void *)maxscaled_pr; + + client_dcb->session = + session_alloc(dcb->session->service, client_dcb); if (poll_add_dcb(client_dcb) == -1) { @@ -313,11 +313,16 @@ maxscaled_close(DCB *dcb) { MAXSCALED *maxscaled = dcb->protocol; - if (maxscaled && maxscaled->username) + if (!maxscaled) + return 0; + + spinlock_acquire(&maxscaled->lock); + if (maxscaled->username) { free(maxscaled->username); maxscaled->username = NULL; } + spinlock_release(&maxscaled->lock); return 0; }