]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
htp layer: use memcap for HTTP related allocations
authorEric Leblond <eric@regit.org>
Mon, 30 Dec 2013 10:06:22 +0000 (11:06 +0100)
committerVictor Julien <victor@inliniac.net>
Fri, 10 Jan 2014 14:21:20 +0000 (15:21 +0100)
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.

src/Makefile.am
src/app-layer-htp-body.c
src/app-layer-htp-libhtp.c
src/app-layer-htp-mem.c [new file with mode: 0644]
src/app-layer-htp-mem.h [new file with mode: 0644]
src/app-layer-htp.c
src/app-layer-htp.h
suricata.yaml.in

index f458f8519bd4b8fd033fd329bdb6e106a6c8c8ae..389edb452af6bd592899ce52653948ea80b48c78 100644 (file)
@@ -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 \
index 3795d1cd209ec4ccdf923f79f444597f161e31a4..173cd07d59f2440d7fea12c035c6ece9a2070423 100644 (file)
@@ -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;
     }
index 41ab1c8b8842d2655fe3a83b8ccc03f81bdeda8a..fbe2df54f8461c4a5fc7cb20dc543694df93044f 100644 (file)
@@ -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 (file)
index 0000000..b21e874
--- /dev/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);
+}
+
+
+/**
+ * @}
+ */
diff --git a/src/app-layer-htp-mem.h b/src/app-layer-htp-mem.h
new file mode 100644 (file)
index 0000000..9cf1f18
--- /dev/null
@@ -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);
index 8678d80d41b9ee44c64e8be259f81382c98cc111..8a765e311d3b36b6acb56b84ad67222daf4b68c0 100644 (file)
@@ -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) {
index db7b56ae7f96746be728ba3829f62472122c7231..864ecaedc0c34d49e5e2e2f3b9507c123088bebf 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "util-radix-tree.h"
 #include "util-file.h"
+#include "app-layer-htp-mem.h"
 
 #include <htp/htp.h>
 
index 7c4747821e5557ba2bff27f9a7057878d3fe7ea6..7222e229dfc010f4b3f387fd27e6cc56aaf49877 100644 (file)
@@ -1055,6 +1055,7 @@ app-layer:
           toserver: 53
     http:
       enabled: yes
+      # memcap: 64mb
 
       ###########################################################################
       # Configure libhtp.