aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Mezger <hannes.mezger@ascolab.com>2018-07-12 18:35:08 +0200
committerAnders Broman <a.broman58@gmail.com>2018-09-14 04:11:20 +0000
commit28a7a79cac425d1b1ecf06e73add41edd2241e49 (patch)
tree499ea77d713811d336279c7741dca2d076bb217e
parentcd95e197ca78feb1e83ec737b87ada0a1dd57d10 (diff)
opcua: prevent opcua dissector crash by limiting nesting depth
The OPC UA types DiagnosticInfo, Variant and ExtensionObject can be nested, which can lead to stack overflows when parsing specially crafted packets. This is fixed by storing the current nesting depth as expert info. The corresponding CVE is https://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-12086 The corresponding security bulletin of the OPC Foundation is https://opcfoundation-onlineapplications.org/faq/SecurityBulletins/OPC_Foundation_Security_Bulletin_CVE-2018-12086.pdf Change-Id: I5f6da3a3e269f6db1b690b77470ddf60045bcedd Reviewed-on: https://code.wireshark.org/review/29645 Petri-Dish: Anders Broman <a.broman58@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--plugins/epan/opcua/opcua.c2
-rw-r--r--plugins/epan/opcua/opcua_simpletypes.c36
2 files changed, 37 insertions, 1 deletions
diff --git a/plugins/epan/opcua/opcua.c b/plugins/epan/opcua/opcua.c
index fc26d9f..4ca68a9 100644
--- a/plugins/epan/opcua/opcua.c
+++ b/plugins/epan/opcua/opcua.c
@@ -38,7 +38,7 @@ void proto_reg_handoff_opcua(void);
/* declare parse function pointer */
typedef int (*FctParse)(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset);
-static int proto_opcua = -1;
+int proto_opcua = -1;
static dissector_handle_t opcua_handle;
/** Official IANA registered port for OPC UA Binary Protocol. */
#define OPCUA_PORT_RANGE "4840"
diff --git a/plugins/epan/opcua/opcua_simpletypes.c b/plugins/epan/opcua/opcua_simpletypes.c
index a787f21..ab006b7 100644
--- a/plugins/epan/opcua/opcua_simpletypes.c
+++ b/plugins/epan/opcua/opcua_simpletypes.c
@@ -20,6 +20,7 @@
#include <epan/packet.h>
#include <epan/expert.h>
#include <epan/dissectors/packet-windows-common.h>
+#include <epan/proto_data.h>
#include "opcua_simpletypes.h"
#include "opcua_hfindeces.h"
#include "opcua_statuscode.h"
@@ -80,6 +81,7 @@
/* Chosen arbitrarily */
#define MAX_ARRAY_LEN 10000
+#define MAX_NESTING_DEPTH 100
static int hf_opcua_diag_mask = -1;
static int hf_opcua_diag_mask_symbolicflag = -1;
@@ -168,6 +170,9 @@ int hf_opcua_resultMask_displayname = -1;
int hf_opcua_resultMask_typedefinition = -1;
static expert_field ei_array_length = EI_INIT;
+static expert_field ei_nesting_depth = EI_INIT;
+
+extern int proto_opcua;
/** NodeId encoding mask table */
static const value_string g_nodeidmasks[] = {
@@ -526,6 +531,7 @@ void registerSimpleTypes(int proto)
static ei_register_info ei[] = {
{ &ei_array_length, { "opcua.array.length", PI_UNDECODED, PI_ERROR, "Max array length exceeded", EXPFILL }},
+ { &ei_nesting_depth, { "opcua.nestingdepth", PI_UNDECODED, PI_ERROR, "Max nesting depth exceeded", EXPFILL }},
};
proto_register_field_array(proto, hf, array_length(hf));
@@ -802,9 +808,19 @@ void parseDiagnosticInfo(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gi
guint8 EncodingMask;
proto_tree *subtree;
proto_item *ti;
+ guint opcua_nested_count;
subtree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, ett_opcua_diagnosticinfo, &ti, "%s: DiagnosticInfo", szFieldName);
+ /* prevent a too high nesting depth */
+ opcua_nested_count = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_opcua, 0));
+ if (++opcua_nested_count > MAX_NESTING_DEPTH)
+ {
+ expert_add_info(pinfo, ti, &ei_nesting_depth);
+ return;
+ }
+ p_add_proto_data(pinfo->pool, pinfo, proto_opcua, 0, GUINT_TO_POINTER(opcua_nested_count));
+
/* parse encoding mask */
EncodingMask = tvb_get_guint8(tvb, iOffset);
proto_tree_add_bitmask(subtree, tvb, iOffset, hf_opcua_diag_mask, ett_opcua_diagnosticinfo_encodingmask, diag_mask, ENC_LITTLE_ENDIAN);
@@ -912,6 +928,16 @@ void parseVariant(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOf
gint iOffset = *pOffset;
guint8 EncodingMask;
gint32 ArrayDimensions = 0;
+ guint opcua_nested_count;
+
+ /* prevent a too high nesting depth */
+ opcua_nested_count = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_opcua, 0));
+ if (++opcua_nested_count > MAX_NESTING_DEPTH)
+ {
+ expert_add_info(pinfo, ti, &ei_nesting_depth);
+ return;
+ }
+ p_add_proto_data(pinfo->pool, pinfo, proto_opcua, 0, GUINT_TO_POINTER(opcua_nested_count));
EncodingMask = tvb_get_guint8(tvb, iOffset);
proto_tree_add_item(subtree, hf_opcua_variant_encodingmask, tvb, iOffset, 1, ENC_LITTLE_ENDIAN);
@@ -1167,10 +1193,20 @@ void parseExtensionObject(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, g
guint32 TypeId;
proto_tree *extobj_tree;
proto_item *ti;
+ guint opcua_nested_count;
/* add extension object subtree */
extobj_tree = proto_tree_add_subtree_format(tree, tvb, *pOffset, -1, ett_opcua_extensionobject, &ti, "%s: ExtensionObject", szFieldName);
+ /* prevent a too high nesting depth */
+ opcua_nested_count = GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_opcua, 0));
+ if (++opcua_nested_count > MAX_NESTING_DEPTH)
+ {
+ expert_add_info(pinfo, ti, &ei_nesting_depth);
+ return;
+ }
+ p_add_proto_data(pinfo->pool, pinfo, proto_opcua, 0, GUINT_TO_POINTER(opcua_nested_count));
+
/* add nodeid subtree */
TypeId = getExtensionObjectType(tvb, &iOffset);
parseExpandedNodeId(extobj_tree, tvb, pinfo, &iOffset, "TypeId");