--- /dev/null
+/* 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 <eric@regit.org>
+ *
+ * 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);
+}
+
+
+/**
+ * @}
+ */
{
SCEnter();
- HtpState *s = SCMalloc(sizeof(HtpState));
+ HtpState *s = HTPMalloc(sizeof(HtpState));
if (unlikely(s == NULL))
goto error;
error:
if (s != NULL) {
- SCFree(s);
+ HTPFree(s, sizeof(HtpState));
}
SCReturnPtr(NULL, "void");
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));
}
}
FileContainerFree(s->files_ts);
FileContainerFree(s->files_tc);
- SCFree(s);
+ HTPFree(s, sizeof(HtpState));
#ifdef DEBUG
SCMutexLock(&htp_state_mem_lock);
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;
}
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;
}
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;
}
error:
if (eb != NULL) {
- SCFree(eb);
+ HTPFree(eb, eb_len);
}
if (ebe != NULL) {
- SCFree(ebe);
+ HTPFree(ebe, ebe_len);
}
SCReturnInt(-1);
}
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;
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;
}
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);
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);
}
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);
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);
}
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;
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);
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);
}
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) {