summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2013-01-02 15:39:42 +0000
committerMatthew Jordan <mjordan@digium.com>2013-01-02 15:39:42 +0000
commit1fb06fde957fb466388c764384c2e14698e2dc15 (patch)
treee21651a29686d658d8dde28c54ddec92946497aa
parent2db81d7fc263ba609bd310b13abbbd8e0d3e3b82 (diff)
Resolve crashes due to large stack allocations when using TCP
Asterisk had several places where messages received over various network transports may be copied in a single stack allocation. In the case of TCP, since multiple packets in a stream may be concatenated together, this can lead to large allocations that overflow the stack. This patch modifies those portions of Asterisk using TCP to either favor heap allocations or use an upper bound to ensure that the stack will not overflow: * For SIP, the allocation now has an upper limit * For HTTP, the allocation is now a heap allocation instead of a stack allocation * For XMPP (in res_jabber), the allocation has been eliminated since it was unnecesary. Note that the HTTP portion of this issue was independently found by Brandon Edwards of Exodus Intelligence. (issue ASTERISK-20658) Reported by: wdoekes, Brandon Edwards Tested by: mmichelson, wdoekes patches: ASTERISK-20658_res_jabber.c.patch uploaded by mmichelson (license 5049) issueA20658_http_postvars_use_malloc2.patch uploaded by wdoekes (license 5674) issueA20658_limit_sip_packet_size3.patch uploaded by wdoekes (license 5674) ........ Merged revisions 378269 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 378286 from http://svn.asterisk.org/svn/asterisk/branches/10 ........ Merged revisions 378287 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@378288 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--channels/chan_sip.c58
-rw-r--r--channels/sip/include/sip.h1
-rw-r--r--main/http.c20
-rw-r--r--res/res_jabber.c5
4 files changed, 60 insertions, 24 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index e1dfd5ddd..b2b3395c7 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -2718,19 +2718,20 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
int authenticated, time_t start, struct sip_threadinfo *me)
{
int res, content_length, after_poll = 1, need_poll = 1;
+ size_t datalen = ast_str_strlen(req->data);
char buf[1024] = "";
int timeout = -1;
-
- /* Read in headers one line at a time */
- while (ast_str_strlen(req->data) < 4 || strncmp(REQ_OFFSET_TO_STR(req, data->used - 4), "\r\n\r\n", 4)) {
- if (!tcptls_session->client && !authenticated) {
- if ((timeout = sip_check_authtimeout(start)) < 0) {
- ast_debug(2, "SIP SSL server failed to determine authentication timeout\n");
+
+ /* Read in headers one line at a time */
+ while (datalen < 4 || strncmp(REQ_OFFSET_TO_STR(req, data->used - 4), "\r\n\r\n", 4)) {
+ if (!tcptls_session->client && !authenticated) {
+ if ((timeout = sip_check_authtimeout(start)) < 0) {
+ ast_debug(2, "SIP TLS server failed to determine authentication timeout\n");
return -1;
}
if (timeout == 0) {
- ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
+ ast_debug(2, "SIP TLS server timed out\n");
return -1;
}
} else {
@@ -2745,11 +2746,11 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
after_poll = 1;
res = ast_wait_for_input(tcptls_session->fd, timeout);
if (res < 0) {
- ast_debug(2, "SIP TCP server :: ast_wait_for_input returned %d\n", res);
+ ast_debug(2, "SIP TLS server :: ast_wait_for_input returned %d\n", res);
return -1;
} else if (res == 0) {
/* timeout */
- ast_debug(2, "SIP TCP server timed out\n");
+ ast_debug(2, "SIP TLS server timed out\n");
return -1;
}
}
@@ -2770,6 +2771,13 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
return -1;
}
ast_str_append(&req->data, 0, "%s", buf);
+
+ datalen = ast_str_strlen(req->data);
+ if (datalen > SIP_MAX_PACKET_SIZE) {
+ ast_log(LOG_WARNING, "Rejecting TLS packet from '%s' because way too large: %zu\n",
+ ast_sockaddr_stringify(&tcptls_session->remote_address), datalen);
+ return -1;
+ }
}
copy_request(reqcpy, req);
parse_request(reqcpy);
@@ -2783,7 +2791,7 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
}
if (timeout == 0) {
- ast_debug(2, "SIP SSL server timed out\n");
+ ast_debug(2, "SIP TLS server timed out\n");
return -1;
}
} else {
@@ -2795,11 +2803,11 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
after_poll = 1;
res = ast_wait_for_input(tcptls_session->fd, timeout);
if (res < 0) {
- ast_debug(2, "SIP TCP server :: ast_wait_for_input returned %d\n", res);
+ ast_debug(2, "SIP TLS server :: ast_wait_for_input returned %d\n", res);
return -1;
} else if (res == 0) {
/* timeout */
- ast_debug(2, "SIP TCP server timed out\n");
+ ast_debug(2, "SIP TLS server timed out\n");
return -1;
}
}
@@ -2822,6 +2830,13 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
}
content_length -= strlen(buf);
ast_str_append(&req->data, 0, "%s", buf);
+
+ datalen = ast_str_strlen(req->data);
+ if (datalen > SIP_MAX_PACKET_SIZE) {
+ ast_log(LOG_WARNING, "Rejecting TLS packet from '%s' because way too large: %zu\n",
+ ast_sockaddr_stringify(&tcptls_session->remote_address), datalen);
+ return -1;
+ }
}
}
/*! \todo XXX If there's no Content-Length or if the content-length and what
@@ -2995,6 +3010,8 @@ static int sip_tcp_read(struct sip_request *req, struct ast_tcptls_session_insta
enum message_integrity message_integrity = MESSAGE_FRAGMENT;
while (message_integrity == MESSAGE_FRAGMENT) {
+ size_t datalen;
+
if (ast_str_strlen(tcptls_session->overflow_buf) == 0) {
char readbuf[4097];
int timeout;
@@ -3034,6 +3051,13 @@ static int sip_tcp_read(struct sip_request *req, struct ast_tcptls_session_insta
ast_str_append(&req->data, 0, "%s", ast_str_buffer(tcptls_session->overflow_buf));
ast_str_reset(tcptls_session->overflow_buf);
}
+
+ datalen = ast_str_strlen(req->data);
+ if (datalen > SIP_MAX_PACKET_SIZE) {
+ ast_log(LOG_WARNING, "Rejecting TCP packet from '%s' because way too large: %zu\n",
+ ast_sockaddr_stringify(&tcptls_session->remote_address), datalen);
+ return -1;
+ }
message_integrity = check_message_integrity(&req->data, &tcptls_session->overflow_buf);
}
@@ -3105,7 +3129,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
}
me->threadid = pthread_self();
- ast_debug(2, "Starting thread for %s server\n", tcptls_session->ssl ? "SSL" : "TCP");
+ ast_debug(2, "Starting thread for %s server\n", tcptls_session->ssl ? "TLS" : "TCP");
/* set up pollfd to watch for reads on both the socket and the alert_pipe */
fds[0].fd = tcptls_session->fd;
@@ -3139,7 +3163,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
}
if (timeout == 0) {
- ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
+ ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "TLS": "TCP");
goto cleanup;
}
} else {
@@ -3149,11 +3173,11 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
if (ast_str_strlen(tcptls_session->overflow_buf) == 0) {
res = ast_poll(fds, 2, timeout); /* polls for both socket and alert_pipe */
if (res < 0) {
- ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res);
+ ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "TLS": "TCP", res);
goto cleanup;
} else if (res == 0) {
/* timeout */
- ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
+ ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "TLS": "TCP");
goto cleanup;
}
}
@@ -3235,7 +3259,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
}
}
- ast_debug(2, "Shutting down thread for %s server\n", tcptls_session->ssl ? "SSL" : "TCP");
+ ast_debug(2, "Shutting down thread for %s server\n", tcptls_session->ssl ? "TLS" : "TCP");
cleanup:
if (tcptls_session && !tcptls_session->client && !authenticated) {
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index 9a818553b..f51ac7749 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -101,6 +101,7 @@
#define SIP_MAX_HEADERS 64 /*!< Max amount of SIP headers to read */
#define SIP_MAX_LINES 256 /*!< Max amount of lines in SIP attachment (like SDP) */
+#define SIP_MAX_PACKET_SIZE 20480 /*!< Max SIP packet size */
#define SIP_MIN_PACKET 4096 /*!< Initialize size of memory to allocate for packets */
#define MAX_HISTORY_ENTRIES 50 /*!< Max entires in the history list for a sip_pvt */
diff --git a/main/http.c b/main/http.c
index 44148edf8..fc2931290 100644
--- a/main/http.c
+++ b/main/http.c
@@ -611,6 +611,7 @@ struct ast_variable *ast_http_get_post_vars(
int content_length = 0;
struct ast_variable *v, *post_vars=NULL, *prev = NULL;
char *buf, *var, *val;
+ int res;
for (v = headers; v; v = v->next) {
if (!strcasecmp(v->name, "Content-Type")) {
@@ -623,20 +624,28 @@ struct ast_variable *ast_http_get_post_vars(
for (v = headers; v; v = v->next) {
if (!strcasecmp(v->name, "Content-Length")) {
- content_length = atoi(v->value) + 1;
+ content_length = atoi(v->value);
break;
}
}
- if (!content_length) {
+ if (content_length <= 0) {
return NULL;
}
- buf = ast_alloca(content_length);
- if (!fgets(buf, content_length, ser->f)) {
+ buf = ast_malloc(content_length + 1);
+ if (!buf) {
return NULL;
}
+ res = fread(buf, 1, content_length, ser->f);
+ if (res < content_length) {
+ /* Error, distinguishable by ferror() or feof(), but neither
+ * is good. */
+ goto done;
+ }
+ buf[content_length] = '\0';
+
while ((val = strsep(&buf, "&"))) {
var = strsep(&val, "=");
if (val) {
@@ -654,6 +663,9 @@ struct ast_variable *ast_http_get_post_vars(
prev = v;
}
}
+
+done:
+ ast_free(buf);
return post_vars;
}
diff --git a/res/res_jabber.c b/res/res_jabber.c
index fa6bbfdbf..fa45fdf6d 100644
--- a/res/res_jabber.c
+++ b/res/res_jabber.c
@@ -785,7 +785,7 @@ static struct ast_custom_function jabberstatus_function = {
*/
static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
{
- char *aux = NULL, *parse = NULL;
+ char *parse = NULL;
int timeout;
int jidlen, resourcelen;
struct timeval start;
@@ -902,7 +902,7 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch
continue;
}
found = 1;
- aux = ast_strdupa(tmp->message);
+ ast_copy_string(buf, tmp->message, buflen);
AST_LIST_REMOVE_CURRENT(list);
aji_message_destroy(tmp);
break;
@@ -927,7 +927,6 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch
ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
return -1;
}
- ast_copy_string(buf, aux, buflen);
return 0;
}