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.
pull/758/head
Eric Leblond 11 years ago committed by Victor Julien
parent ba4758d033
commit ced01da822

@ -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 \

@ -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;
}

@ -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;

@ -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 <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);
}
/**
* @}
*/

@ -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);

@ -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) {

@ -35,6 +35,7 @@
#include "util-radix-tree.h"
#include "util-file.h"
#include "app-layer-htp-mem.h"
#include <htp/htp.h>

@ -1055,6 +1055,7 @@ app-layer:
toserver: 53
http:
enabled: yes
# memcap: 64mb
###########################################################################
# Configure libhtp.

Loading…
Cancel
Save