diff --git a/src/Makefile.am b/src/Makefile.am index f458f8519b..389edb452a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,7 @@ app-layer-htp-body.c app-layer-htp-body.h \ app-layer-htp.c app-layer-htp.h \ app-layer-htp-file.c app-layer-htp-file.h \ app-layer-htp-libhtp.c app-layer-htp-libhtp.h \ +app-layer-htp-mem.c app-layer-htp-mem.h \ app-layer-parser.c app-layer-parser.h \ app-layer-protos.c app-layer-protos.h \ app-layer-smb2.c app-layer-smb2.h \ diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index 3795d1cd20..173cd07d59 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -85,7 +85,7 @@ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32 if (body->first == NULL) { /* New chunk */ - bd = (HtpBodyChunk *)SCMalloc(sizeof(HtpBodyChunk)); + bd = (HtpBodyChunk *)HTPMalloc(sizeof(HtpBodyChunk)); if (bd == NULL) goto error; @@ -93,7 +93,7 @@ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32 bd->stream_offset = 0; bd->next = NULL; - bd->data = SCMalloc(len); + bd->data = HTPMalloc(len); if (bd->data == NULL) { goto error; } @@ -103,7 +103,7 @@ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32 body->content_len_so_far = len; } else { - bd = (HtpBodyChunk *)SCMalloc(sizeof(HtpBodyChunk)); + bd = (HtpBodyChunk *)HTPMalloc(sizeof(HtpBodyChunk)); if (bd == NULL) goto error; @@ -111,7 +111,7 @@ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32 bd->stream_offset = body->content_len_so_far; bd->next = NULL; - bd->data = SCMalloc(len); + bd->data = HTPMalloc(len); if (bd->data == NULL) { goto error; } @@ -129,9 +129,9 @@ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32 error: if (bd != NULL) { if (bd->data != NULL) { - SCFree(bd->data); + HTPFree(bd->data, bd->len); } - SCFree(bd); + HTPFree(bd, sizeof(HtpBodyChunk)); } SCReturnInt(-1); } @@ -183,8 +183,8 @@ void HtpBodyFree(HtpBody *body) while (prev != NULL) { cur = prev->next; if (prev->data != NULL) - SCFree(prev->data); - SCFree(prev); + HTPFree(prev->data, prev->len); + HTPFree(prev, sizeof(HtpBodyChunk)); prev = cur; } body->first = body->last = NULL; @@ -230,9 +230,9 @@ void HtpBodyPrune(HtpBody *body) } if (cur->data != NULL) { - SCFree(cur->data); + HTPFree(cur->data, cur->len); } - SCFree(cur); + HTPFree(cur, sizeof(HtpBodyChunk)); cur = next; } diff --git a/src/app-layer-htp-libhtp.c b/src/app-layer-htp-libhtp.c index 41ab1c8b88..fbe2df54f8 100644 --- a/src/app-layer-htp-libhtp.c +++ b/src/app-layer-htp-libhtp.c @@ -159,6 +159,7 @@ bstr *SCHTPGenerateNormalizedUri(htp_tx_t *tx, htp_uri_t *uri, int uri_include_a } // On the second pass construct the string + /* FIXME in memcap */ bstr *r = bstr_alloc(len); if (r == NULL) { return NULL; diff --git a/src/app-layer-htp-mem.c b/src/app-layer-htp-mem.c new file mode 100644 index 0000000000..b21e874ced --- /dev/null +++ b/src/app-layer-htp-mem.c @@ -0,0 +1,130 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +/** + * \file + * + * \author Eric Leblond + * + * This file provides a memory handling for the HTTP protocol support. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "conf.h" +#include "util-mem.h" +#include "util-misc.h" + +uint64_t htp_config_memcap = 0; + +SC_ATOMIC_DECLARE(uint64_t, htp_memuse); + +void HTPParseMemcap() +{ + char *conf_val; + + /** set config values for memcap, prealloc and hash_size */ + if ((ConfGet("app-layer.protocols.http.memcap", &conf_val)) == 1) + { + if (ParseSizeStringU64(conf_val, &htp_config_memcap) < 0) { + SCLogError(SC_ERR_SIZE_PARSE, "Error parsing http.memcap " + "from conf file - %s. Killing engine", + conf_val); + exit(EXIT_FAILURE); + } + } else { + /* default to unlimited */ + htp_config_memcap = 0; + } +} + +void HTPIncrMemuse(uint64_t size) +{ + (void) SC_ATOMIC_ADD(htp_memuse, size); + return; +} + +void HTPDecrMemuse(uint64_t size) +{ + (void) SC_ATOMIC_SUB(htp_memuse, size); + return; +} + +/** + * \brief Check if alloc'ing "size" would mean we're over memcap + * + * \retval 1 if in bounds + * \retval 0 if not in bounds + */ +int HTPCheckMemcap(uint64_t size) +{ + if (htp_config_memcap == 0 || size + SC_ATOMIC_GET(htp_memuse) <= htp_config_memcap) + return 1; + return 0; +} + +void *HTPMalloc(size_t size) +{ + void *ptr = NULL; + + if (HTPCheckMemcap((uint32_t)size) == 0) + return NULL; + + ptr = SCMalloc(size); + + if (unlikely(ptr == NULL)) + return NULL; + + HTPIncrMemuse((uint64_t)size); + + return ptr; +} + +void *HTPRealloc(void *ptr, size_t orig_size, size_t size) +{ + void *rptr = NULL; + + if (HTPCheckMemcap((uint32_t)(size - orig_size)) == 0) + return NULL; + + rptr = SCRealloc(ptr, size); + if (rptr == NULL) + return NULL; + + HTPIncrMemuse((uint64_t)(size - orig_size)); + + return rptr; +} + +void HTPFree(void *ptr, size_t size) +{ + SCFree(ptr); + + HTPDecrMemuse((uint64_t)size); +} + + +/** + * @} + */ diff --git a/src/app-layer-htp-mem.h b/src/app-layer-htp-mem.h new file mode 100644 index 0000000000..9cf1f18f40 --- /dev/null +++ b/src/app-layer-htp-mem.h @@ -0,0 +1,21 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +void HTPParseMemcap(); +void *HTPMalloc(size_t size); +void *HTPRealloc(void *ptr, size_t orig_size, size_t size); +void HTPFree(void *ptr, size_t size); diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 8678d80d41..8a765e311d 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -236,7 +236,7 @@ static void *HTPStateAlloc(void) { SCEnter(); - HtpState *s = SCMalloc(sizeof(HtpState)); + HtpState *s = HTPMalloc(sizeof(HtpState)); if (unlikely(s == NULL)) goto error; @@ -254,7 +254,7 @@ static void *HTPStateAlloc(void) error: if (s != NULL) { - SCFree(s); + HTPFree(s, sizeof(HtpState)); } SCReturnPtr(NULL, "void"); @@ -266,12 +266,12 @@ static void HtpTxUserDataFree(HtpTxUserData *htud) { HtpBodyFree(&htud->response_body); bstr_free(htud->request_uri_normalized); if (htud->request_headers_raw) - SCFree(htud->request_headers_raw); + HTPFree(htud->request_headers_raw, htud->request_headers_raw_len); if (htud->response_headers_raw) - SCFree(htud->response_headers_raw); + HTPFree(htud->response_headers_raw, htud->response_headers_raw_len); if (htud->boundary) - SCFree(htud->boundary); - SCFree(htud); + HTPFree(htud->boundary, htud->boundary_len); + HTPFree(htud, sizeof(HtpTxUserData)); } } @@ -314,7 +314,7 @@ void HTPStateFree(void *state) FileContainerFree(s->files_ts); FileContainerFree(s->files_tc); - SCFree(s); + HTPFree(s, sizeof(HtpState)); #ifdef DEBUG SCMutexLock(&htp_state_mem_lock); @@ -1011,7 +1011,7 @@ static int HtpRequestBodySetupMultipart(htp_tx_data_t *d, HtpTxUserData *htud) { printf("BOUNDARY END: \n"); #endif if (boundary_len < HTP_BOUNDARY_MAX) { - htud->boundary = SCMalloc(boundary_len); + htud->boundary = HTPMalloc(boundary_len); if (htud->boundary == NULL) { return -1; } @@ -1040,7 +1040,7 @@ static int HtpRequestBodySetupBoundary(HtpTxUserData *htud, uint8_t *ebe = NULL; uint8_t eb_len = htud->boundary_len + 2; - eb = (uint8_t *)SCMalloc(eb_len); + eb = (uint8_t *)HTPMalloc(eb_len); if (eb == NULL) { goto error; } @@ -1048,7 +1048,7 @@ static int HtpRequestBodySetupBoundary(HtpTxUserData *htud, memcpy(eb + 2, htud->boundary, htud->boundary_len); uint8_t ebe_len = htud->boundary_len + 4; - ebe = (uint8_t *)SCMalloc(ebe_len); + ebe = (uint8_t *)HTPMalloc(ebe_len); if (ebe == NULL) { goto error; } @@ -1064,10 +1064,10 @@ static int HtpRequestBodySetupBoundary(HtpTxUserData *htud, error: if (eb != NULL) { - SCFree(eb); + HTPFree(eb, eb_len); } if (ebe != NULL) { - SCFree(ebe); + HTPFree(ebe, ebe_len); } SCReturnInt(-1); } @@ -1192,8 +1192,8 @@ static void HtpRequestBodyReassemble(HtpTxUserData *htud, uint8_t *pbuf = NULL; buf_len += tlen; - if ((pbuf = SCRealloc(buf, buf_len)) == NULL) { - SCFree(buf); + if ((pbuf = HTPRealloc(buf, buf_len - tlen, buf_len)) == NULL) { + HTPFree(buf, buf_len - tlen); buf = NULL; buf_len = 0; break; @@ -1205,8 +1205,8 @@ static void HtpRequestBodyReassemble(HtpTxUserData *htud, SCLogDebug("use entire chunk"); buf_len += cur->len; - if ((pbuf = SCRealloc(buf, buf_len)) == NULL) { - SCFree(buf); + if ((pbuf = HTPRealloc(buf, buf_len - cur->len, buf_len)) == NULL) { + HTPFree(buf, buf_len - cur->len); buf = NULL; buf_len = 0; break; @@ -1499,10 +1499,10 @@ next: } end: if (expected_boundary != NULL) { - SCFree(expected_boundary); + HTPFree(expected_boundary, expected_boundary_len); } if (expected_boundary_end != NULL) { - SCFree(expected_boundary_end); + HTPFree(expected_boundary_end, expected_boundary_end_len); } SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed); @@ -1726,7 +1726,7 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(d->tx); if (tx_ud == NULL) { - tx_ud = SCMalloc(sizeof(HtpTxUserData)); + tx_ud = HTPMalloc(sizeof(HtpTxUserData)); if (unlikely(tx_ud == NULL)) { SCReturnInt(HTP_OK); } @@ -1795,7 +1795,7 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) HtpRequestBodyHandleMultipart(hstate, tx_ud, d->tx, chunks_buffer, chunks_buffer_len); if (chunks_buffer != NULL) { - SCFree(chunks_buffer); + HTPFree(chunks_buffer, chunks_buffer_len); } } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST) { HtpRequestBodyHandlePOST(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); @@ -1840,7 +1840,7 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(d->tx); if (tx_ud == NULL) { - tx_ud = SCMalloc(sizeof(HtpTxUserData)); + tx_ud = HTPMalloc(sizeof(HtpTxUserData)); if (unlikely(tx_ud == NULL)) { SCReturnInt(HTP_OK); } @@ -2013,7 +2013,7 @@ static int HTPCallbackRequestLine(htp_tx_t *tx) if (request_uri_normalized == NULL) return HTP_OK; - tx_ud = SCMalloc(sizeof(*tx_ud)); + tx_ud = HTPMalloc(sizeof(*tx_ud)); if (unlikely(tx_ud == NULL)) { bstr_free(request_uri_normalized); return HTP_OK; @@ -2058,16 +2058,17 @@ static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); if (tx_ud == NULL) { - tx_ud = SCMalloc(sizeof(*tx_ud)); + tx_ud = HTPMalloc(sizeof(*tx_ud)); if (unlikely(tx_ud == NULL)) return HTP_OK; memset(tx_ud, 0, sizeof(*tx_ud)); htp_tx_set_user_data(tx_data->tx, tx_ud); } - ptmp = SCRealloc(tx_ud->request_headers_raw, + ptmp = HTPRealloc(tx_ud->request_headers_raw, + tx_ud->request_headers_raw_len, tx_ud->request_headers_raw_len + tx_data->len); if (ptmp == NULL) { - SCFree(tx_ud->request_headers_raw); + HTPFree(tx_ud->request_headers_raw, tx_ud->request_headers_raw_len); tx_ud->request_headers_raw = NULL; tx_ud->request_headers_raw_len = 0; HtpTxUserDataFree(tx_ud); @@ -2095,16 +2096,17 @@ static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); if (tx_ud == NULL) { - tx_ud = SCMalloc(sizeof(*tx_ud)); + tx_ud = HTPMalloc(sizeof(*tx_ud)); if (unlikely(tx_ud == NULL)) return HTP_OK; memset(tx_ud, 0, sizeof(*tx_ud)); htp_tx_set_user_data(tx_data->tx, tx_ud); } - ptmp = SCRealloc(tx_ud->response_headers_raw, + ptmp = HTPRealloc(tx_ud->response_headers_raw, + tx_ud->response_headers_raw_len, tx_ud->response_headers_raw_len + tx_data->len); if (ptmp == NULL) { - SCFree(tx_ud->response_headers_raw); + HTPFree(tx_ud->response_headers_raw, tx_ud->response_headers_raw_len); tx_ud->response_headers_raw = NULL; tx_ud->response_headers_raw_len = 0; HtpTxUserDataFree(tx_ud); @@ -2458,6 +2460,8 @@ void HTPConfigure(void) } HTPConfigSetDefaultsPhase2("default", &cfglist); + HTPParseMemcap(); + /* Read server config and create a parser for each IP in radix tree */ ConfNode *server_config = ConfGetNode("app-layer.protocols.http.libhtp.server-config"); if (server_config == NULL) { diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index db7b56ae7f..864ecaedc0 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -35,6 +35,7 @@ #include "util-radix-tree.h" #include "util-file.h" +#include "app-layer-htp-mem.h" #include diff --git a/suricata.yaml.in b/suricata.yaml.in index 7c4747821e..7222e229df 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1055,6 +1055,7 @@ app-layer: toserver: 53 http: enabled: yes + # memcap: 64mb ########################################################################### # Configure libhtp.