aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fuzz/fuzz_config.cpp20
-rw-r--r--src/lib/ndpi_utils.c1
-rw-r--r--src/lib/third_party/src/fuzz/pl7m.c186
3 files changed, 203 insertions, 4 deletions
diff --git a/fuzz/fuzz_config.cpp b/fuzz/fuzz_config.cpp
index 647ee4a7b..fe067aa5f 100644
--- a/fuzz/fuzz_config.cpp
+++ b/fuzz/fuzz_config.cpp
@@ -20,8 +20,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
struct ndpi_patricia_tree_stats patricia_stats;
struct ndpi_automa_stats automa_stats;
int cat, idx;
- u_int16_t pid;
- char *protoname;
+ u_int16_t pid, pid2;
+ char *protoname, *protoname2;
+ char pids_name[32];
const char *name;
char catname[] = "name";
struct ndpi_flow_input_info input_info;
@@ -486,7 +487,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
pid = fuzzed_data.ConsumeIntegralInRange<u_int16_t>(0, NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + 1); /* + 1 to trigger invalid pid */
protoname = ndpi_get_proto_by_id(ndpi_info_mod, pid);
if (protoname) {
- assert(ndpi_get_proto_by_name(ndpi_info_mod, protoname) == pid);
+ ndpi_get_proto_by_name(ndpi_info_mod, protoname);
+
+ pid2 = fuzzed_data.ConsumeIntegralInRange<u_int16_t>(0, NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + 1); /* + 1 to trigger invalid pid */
+ protoname2 = ndpi_get_proto_by_id(ndpi_info_mod, pid2);
+ if(protoname2) {
+ snprintf(pids_name, sizeof(pids_name), "%s.%s", protoname, protoname2);
+ pids_name[sizeof(pids_name) - 1] = '\0';
+ ndpi_get_protocol_by_name(ndpi_info_mod, pids_name);
+ }
}
ndpi_map_user_proto_id_to_ndpi_id(ndpi_info_mod, pid);
ndpi_map_ndpi_id_to_user_proto_id(ndpi_info_mod, pid);
@@ -549,6 +558,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_get_ip_proto_name(fuzzed_data.ConsumeIntegral<u_int8_t>(), NULL, 0);
}
ndpi_risk2str(static_cast<ndpi_risk_enum>(fuzzed_data.ConsumeIntegral<u_int64_t>()));
+ ndpi_risk2code(static_cast<ndpi_risk_enum>(fuzzed_data.ConsumeIntegral<u_int64_t>()));
+ ndpi_code2risk(ndpi_risk2code(static_cast<ndpi_risk_enum>(fuzzed_data.ConsumeIntegralInRange(0, NDPI_MAX_RISK + 1))));
ndpi_severity2str(static_cast<ndpi_risk_severity>(fuzzed_data.ConsumeIntegral<u_int8_t>()));
ndpi_risk2score(static_cast<ndpi_risk_enum>(fuzzed_data.ConsumeIntegral<u_int64_t>()), &unused1, &unused2);
ndpi_http_method2str(static_cast<ndpi_http_method>(fuzzed_data.ConsumeIntegral<u_int8_t>()));
@@ -619,6 +630,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
{ NDPI_PARAM_ISSUER_DN, (void *)("CN=813845657003339838, O=Code42, OU=TEST, ST=MN, C=US") /* from example/protos.txt */},
{ NDPI_PARAM_HOST_IPV4, &flow.c_address.v4} };
ndpi_check_flow_risk_exceptions(ndpi_info_mod, 3, params);
+
+ ndpi_risk_params params2[] = { { NDPI_MAX_RISK_PARAM_ID, &flow.c_address.v4} }; /* Invalid */
+ ndpi_check_flow_risk_exceptions(ndpi_info_mod, 1, params2);
}
/* TODO: stub for geo stuff */
ndpi_get_geoip_asn(ndpi_info_mod, NULL, NULL);
diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c
index 69129fa3e..dfe6cf1f5 100644
--- a/src/lib/ndpi_utils.c
+++ b/src/lib/ndpi_utils.c
@@ -2473,7 +2473,6 @@ ndpi_http_method ndpi_http_str2method(const char* method, u_int16_t method_len)
return(NDPI_HTTP_METHOD_MOVE);
else
return(NDPI_HTTP_METHOD_MKCOL);
- break;
case 'P':
switch(method[1]) {
diff --git a/src/lib/third_party/src/fuzz/pl7m.c b/src/lib/third_party/src/fuzz/pl7m.c
index bf502b642..827e538e7 100644
--- a/src/lib/third_party/src/fuzz/pl7m.c
+++ b/src/lib/third_party/src/fuzz/pl7m.c
@@ -159,6 +159,39 @@ struct gre_header {
__u16 protocol;
};
+#define GTP_MSG_TPDU 0xFF
+
+struct gtp_header {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u_int16_t n_pdu:1,
+ sequence:1,
+ extension:1,
+ reserved:1,
+ protocol:1,
+ version:3,
+ type:8;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u_int16_t version:3,
+ protocol:1,
+ reserved:1,
+ extension:1,
+ sequence:1,
+ n_pdu:1,
+ type:8;
+#else
+#error "Adjust your <asm/byteorder.h> defines"
+#endif
+ u_int16_t total_length;
+ u_int32_t teid;
+};
+
+struct gtp_header_optional {
+ u_int16_t sn;
+ u_int8_t n_pdu_nbr;
+ u_int8_t next_hdr;
+};
+
+
struct m_pkt {
unsigned char *raw_data;
struct pcap_pkthdr header;
@@ -166,6 +199,7 @@ struct m_pkt {
int l2_offset;
int prev_l3_offset;
u_int16_t prev_l3_proto;
+ int gtp_offset;
int l3_offset;
u_int16_t l3_proto;
int l4_offset;
@@ -298,9 +332,13 @@ static int dissect_l2(int datalink_type, struct m_pkt *p)
case DLT_PPP:
case DLT_C_HDLC:
if (data[l2_offset + 0] == 0x0f || data[l2_offset + 0] == 0x8f) {
+ if (data_len < l2_offset + 4)
+ return -1;
l3_offset = 4;
l3_proto = ntohs(*((u_int16_t *)&data[l2_offset + 2]));
} else {
+ if (data_len < l2_offset + 2)
+ return -1;
l3_offset = l2_offset + 2;
next = ntohs(*((u_int16_t *)&data[l2_offset + 0]));
switch (next) {
@@ -704,6 +742,136 @@ static int dissect_l4(struct m_pkt *p)
}
return 0;
}
+static int is_gtp_u(unsigned char *gtp_buffer, int gtp_buffer_len,
+ const struct m_pkt *p, u_int16_t *l3_proto)
+{
+ struct gtp_header *gtp_h;
+ struct udphdr *udp_h;
+ uint16_t new_layer_len = 0;
+ unsigned char sub_proto;
+
+ if (p->l4_proto != IPPROTO_UDP ||
+ gtp_buffer_len < (int)sizeof(struct gtp_header))
+ return 0;
+
+ /* Only default port */
+ udp_h = (struct udphdr *)(p->raw_data + p->l4_offset);
+ if(udp_h->source != htons(2152) &&
+ udp_h->dest != htons(2152))
+ return 0;
+
+ gtp_h = (struct gtp_header *)gtp_buffer;
+
+ if (gtp_h->version != 1 ||
+ gtp_h->type != GTP_MSG_TPDU ||
+ gtp_h->reserved != 0 ||
+ ntohs(gtp_h->total_length) > (gtp_buffer_len - sizeof(struct gtp_header))) {
+ ddbg("Invalid gtp header: %d, 0x%x, 0x%0x, %d vs %d\n",
+ gtp_h->version, gtp_h->type, gtp_h->reserved,
+ ntohs(gtp_h->total_length), gtp_buffer_len);
+ return 0;
+ }
+
+ new_layer_len = sizeof(struct gtp_header);
+
+ /* Optional header version 1 */
+ if (gtp_h->extension || gtp_h->sequence || gtp_h->n_pdu) {
+ new_layer_len += sizeof(struct gtp_header_optional);
+
+ if (gtp_buffer_len < new_layer_len)
+ return 0;
+ }
+ if (gtp_h->extension) {
+ unsigned int length = 0;
+
+ while (new_layer_len < (gtp_buffer_len - 1)) {
+ length = gtp_buffer[new_layer_len] << 2;
+ new_layer_len += length;
+ if (new_layer_len > gtp_buffer_len ||
+ gtp_buffer[new_layer_len - 1] == 0 || length == 0)
+ break;
+ }
+ if (new_layer_len > gtp_buffer_len ||
+ gtp_buffer[new_layer_len - 1] != 0 ||
+ length == 0) {
+ return 0;
+ }
+ }
+
+ /* Trying to detect next proto. Code taken from wireshark */
+ if (gtp_buffer_len < new_layer_len + 1)
+ return 0;
+ sub_proto = gtp_buffer[new_layer_len];
+ if ((sub_proto >= 0x45) && (sub_proto <= 0x4e)) {
+ /* This is most likely an IPv4 packet
+ * we can exclude 0x40 - 0x44 because the minimum header size is 20 octets
+ * 0x4f is excluded because PPP protocol type "IPv6 header compression"
+ * with protocol field compression is more likely than a plain
+ * IPv4 packet with 60 octet header size */
+ *l3_proto = ETH_P_IP;
+ } else if ((sub_proto & 0xf0) == 0x60) {
+ /* This is most likely an IPv6 packet */
+ *l3_proto = ETH_P_IPV6;
+ } else {
+ /* This seems to be a PPP packet */
+ /* TODO: code not back-ported from wireshark yet*/
+ return 0;
+ }
+
+ return new_layer_len;
+}
+static int dissect_l4_detunneling(struct m_pkt *p)
+{
+ unsigned char *data = p->raw_data + p->l5_offset;
+ int data_len = p->header.caplen - p->l5_offset;
+ u_int16_t next_l3_proto;
+ int gtp_header_len, rc;
+
+ ddbg("L4(detunel): l4_proto %d data_len %d l5_length %d\n",
+ p->l4_proto, data_len, p->l5_length);
+
+ if (data_len < 0 || p->l5_length > data_len)
+ return -1;
+
+ /* TODO: try to handle tunnel over fragment */
+ if (p->is_l3_fragment) {
+ ddbg("Skip L4(detunnel) dissection because it is a fragment\n");
+ return 0;
+ }
+ /* No reasons to detunnel if we skipped L4 dissection */
+ if (p->skip_l4_dissection) {
+ ddbg("Skip L4 dissection\n");
+ return 0;
+ }
+
+ /* GTP detunneling: looking only for MSG T-PDU that carries
+ encapsulated data */
+ gtp_header_len = is_gtp_u(data, data_len, p, &next_l3_proto);
+ if (gtp_header_len > 0) {
+ ddbg("Found GTP-U\n");
+ if (p->prev_l3_proto == 0) {
+ assert(p->prev_l3_offset == 0);
+ p->prev_l3_proto = p->l3_proto;
+ p->prev_l3_offset = p->l3_offset;
+ } else {
+ derr("Multiple tunnels. Unsupported\n");
+ return -1;
+ }
+ assert(p->gtp_offset == 0);
+ p->gtp_offset = p->l5_offset;
+ p->l3_proto = next_l3_proto;
+ p->l3_offset = p->l5_offset + gtp_header_len;
+ rc = dissect_l3(p);
+ if (rc != 0) {
+ derr("Error dissect_l3 (after gtp)\n");
+ return -1;
+ }
+ return dissect_l4(p);
+ }
+
+ /* "Normal" L4 traffic */
+ return 0;
+}
static int dissect_do(int datalink_type, struct m_pkt *p)
{
int rc;
@@ -723,6 +891,12 @@ static int dissect_do(int datalink_type, struct m_pkt *p)
derr("Error dissect_l4\n");
return -1;
}
+ /* Some kind of detunneling over L4 (usually over UDP). Example: GTP */
+ rc = dissect_l4_detunneling(p);
+ if (rc != 0) {
+ derr("Error dissect_l5\n");
+ return -1;
+ }
return 0;
}
@@ -788,6 +962,7 @@ static void update_do_l7(struct m_pkt *p)
{
struct udphdr *udp_h;
struct tcphdr *tcp_h;
+ struct gtp_header *gtp_h;
size_t new_l5_len;
int l4_header_len = 0;
int l5_len_diff;
@@ -853,6 +1028,16 @@ static void update_do_l7(struct m_pkt *p)
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) + l5_len_diff);
}
+ /* Update GTP header */
+ if (p->gtp_offset) {
+ gtp_h = (struct gtp_header *)(p->raw_data + p->gtp_offset);
+ gtp_h->total_length = htons(ntohs(gtp_h->total_length) + l5_len_diff);
+ /* Update previous UDP header */
+ assert(p->gtp_offset > (int)sizeof(struct udphdr));
+ udp_h = (struct udphdr *)(p->raw_data + p->gtp_offset - sizeof(struct udphdr));
+ udp_h->len = htons(ntohs(udp_h->len) + l5_len_diff);
+ }
+
p->l5_length = new_l5_len;
ddbg("cap_len %u->%zu\n", p->header.caplen, p->l5_offset + new_l5_len);
p->header.caplen = p->l5_offset + new_l5_len;
@@ -951,6 +1136,7 @@ static struct m_pkt *__dup_pkt(struct m_pkt *p)
n->l2_offset = p->l2_offset;
n->prev_l3_offset = p->prev_l3_offset;
n->prev_l3_proto = p->prev_l3_proto;
+ n->gtp_offset = p->gtp_offset;
n->l4_offset = p->l4_offset;
n->l3_offset = p->l3_offset;
n->l3_proto = p->l3_proto;