From: Eric Leblond Date: Mon, 30 Dec 2013 10:06:22 +0000 (+0100) Subject: htp layer: use memcap for HTTP related allocations X-Git-Tag: suricata-2.0rc1~232 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ced01da822d0a2e502f191293dc09c5a236b8800;p=thirdparty%2Fsuricata.git htp layer: use memcap for HTTP related allocations This patch introduces wrapper functions around allocation functions to be able to have a global HTP memcap. A simple subsitution of function was not enough because allocated size needed to be known during freeing and reallocation. The value of the memcap can be set in the YAML and is left by default to unlimited (0) to avoid any surprise to users. --- 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.