From 631764757cad77c2bcb3fbbf775c75e90ad5272e Mon Sep 17 00:00:00 2001 From: Filip Matusiak <filip.matusiak@iopsys.eu> Date: Mon, 21 Feb 2022 16:54:44 +0100 Subject: [PATCH] map-agent: Sanitize ap autoconfig WSC CMDU --- src/agent_map.c | 18 +---- src/cmdu_validate.c | 181 +++++++++++++++++++++++++++++++++++++++++++- src/cmdu_validate.h | 1 + 3 files changed, 182 insertions(+), 18 deletions(-) diff --git a/src/agent_map.c b/src/agent_map.c index d03bd4816..23c97562d 100644 --- a/src/agent_map.c +++ b/src/agent_map.c @@ -1635,33 +1635,23 @@ int agent_disable_traffic_separation(struct agent *a) int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu) { struct agent *a = (struct agent *) agent; - struct tlv_policy a_policy[] = { - [0] = { .type = MAP_TLV_DEFAULT_8021Q_SETTINGS, .present = TLV_PRESENT_ONE }, - [1] = { .type = MAP_TLV_TRAFFIC_SEPARATION_POLICY, .present = TLV_PRESENT_ONE }, - [2] = { .type = MAP_TLV_AP_RADIO_IDENTIFIER, .present = TLV_PRESENT_ONE }, - [3] = { .type = TLV_TYPE_WSC, .present = TLV_PRESENT_NUM } - }; uint8_t bssid[6]; - //struct tlv *tlv = NULL; struct wifi_radio_element *radio; - struct tlv *tv[4][16] = {0}; int ret = 0, num = 0; trace("%s: --->\n", __func__); if (memcmp(rx_cmdu->origin, a->cntlr_almac, 6)) { - dbg("|%s:%d| response was not from active controller!\n", + dbg("|%s:%d| response not from an active controller!\n", __func__, __LINE__); return -1; } - - - ret = cmdu_parse_tlvs(rx_cmdu, tv, a_policy, 4); - - if (!tv[2][0] || !tv[3][0]) + if (!validate_ap_autoconfig_wsc(rx_cmdu, tv)) { + dbg("cmdu validation: [AP_AUTOCONFIG_WSC] failed\n"); return -1; + } if (tv[0][0]) { struct tlv_default_8021q_settings *tlv = (struct tlv_default_8021q_settings *) tv[0][0]->data; diff --git a/src/cmdu_validate.c b/src/cmdu_validate.c index 8754f67bb..b58bafe0d 100644 --- a/src/cmdu_validate.c +++ b/src/cmdu_validate.c @@ -7,6 +7,8 @@ #include "utils/debug.h" #include <string.h> +#include <stdio.h> +#include <stdlib.h> bool validate_channel_scan_request(struct cmdu_buff *cmdu, struct tlv *tv[][16]) { @@ -79,8 +81,6 @@ bool validate_channel_scan_request(struct cmdu_buff *cmdu, struct tlv *tv[][16]) bool validate_topology_response(struct cmdu_buff *cmdu, struct tlv *tv[][16]) { - trace("%s: --->\n", __func__); - int ret = 0; struct tlv_policy a_policy[] = { [0] = { .type = TLV_TYPE_DEVICE_INFORMATION_TYPE, @@ -119,8 +119,8 @@ bool validate_topology_response(struct cmdu_buff *cmdu, struct tlv *tv[][16]) } }; - trace("validating topology response |" MACFMT "|CMDU: topology response\n", - MAC2STR(cmdu->origin)); + trace("%s |" MACFMT "|CMDU: topology response\n", + __func__, MAC2STR(cmdu->origin)); ret = cmdu_parse_tlvs(cmdu, tv, a_policy, 11); if (ret) { @@ -200,3 +200,176 @@ bool validate_topology_response(struct cmdu_buff *cmdu, struct tlv *tv[][16]) return true; } + +#define ATTR_MSG_TYPE (0x1022) +#define MSG_TYPE_M2 (0x05) +static int validate_wsc_m2(uint8_t *m2, uint16_t m2_size) +{ + uint8_t *data; + uint8_t *m2_end; + bool ret = false; + + if (!m2 || !m2_size) + return -1; + + data = m2; + m2_end = m2 + m2_size; + + while (abs(data - m2) < m2_size - 4) { + uint16_t attr_type; + uint16_t attr_len; + + attr_type = buf_get_be16(data); + data += 2; + attr_len = buf_get_be16(data); + data += 2; + + if (data + attr_len > m2_end) { + dbg("%s: parse_wsc_m2 failed\n", __func__); + ret = false; + break; + } + + if (attr_type == ATTR_MSG_TYPE) { + if (attr_len != 1) { + ret = false; + break; + } + if (*data == MSG_TYPE_M2) + ret = true; + } + + data += attr_len; + } + + /* true if msg type is M2 & data never goes OOB */ + return ret; +} + +bool validate_ap_autoconfig_wsc(struct cmdu_buff *cmdu, struct tlv *tv[][16]) +{ + struct tlv_policy a_policy[] = { + [0] = { .type = MAP_TLV_DEFAULT_8021Q_SETTINGS, + .present = TLV_PRESENT_ONE, + .minlen = 3, /* tlv_default_8021q_settings */ + }, + [1] = { .type = MAP_TLV_TRAFFIC_SEPARATION_POLICY, + .present = TLV_PRESENT_ONE, + .minlen = 1, /* tlv_traffic_sep_policy: num_ssid */ + }, + [2] = { .type = MAP_TLV_AP_RADIO_IDENTIFIER, + .present = TLV_PRESENT_ONE, + .minlen = 6, /* bssid */ + .maxlen = 6, + }, + [3] = { .type = TLV_TYPE_WSC, + .present = TLV_PRESENT_NUM + } + }; + int num = 0; + int ret; + + trace("%s |" MACFMT "|CMDU: ap autoconfig WSC\n", + __func__, MAC2STR(cmdu->origin)); + + ret = cmdu_parse_tlvs(cmdu, tv, a_policy, 4); + if (ret) { + dbg("%s: parse_tlv failed\n", __func__); + return false; + } + + if (!tv[2][0] || !tv[3][0]) { + dbg("%s: Missing one or more mandatory TLV!\n", __func__); + return false; + } + + /* Parse Default 802.1Q Settings TLV */ + if (tv[0][0]) { + struct tlv_default_8021q_settings *tlv; + uint16_t tlv_len = tlv_length(tv[0][0]); + + if (tlv_len != sizeof(struct tlv_default_8021q_settings)) + return false; + + tlv = (struct tlv_default_8021q_settings *)tv[0][0]->data; + if (!tlv) + return false; + } + + /* Parse Traffic Separation Policy TLV */ + if (tv[1][0]) { + int i, offset = 0; + uint8_t *tv_data; + uint8_t num_ssid; + uint16_t tlv_len = tlv_length(tv[1][0]); + + if (!tlv_len) + return false; + + tv_data = (uint8_t *)tv[1][0]->data; + if (!tv_data) + return false; + + /* num_ssid (1 byte) */ + if (offset + 1 > tlv_len) + return false; + + num_ssid = tv_data[offset++]; + + for (i = 0; i < num_ssid; i++) { + int ssid_len; + + /* ssid_len (1 byte) */ + if (offset + 1 > tlv_len) + return false; + + ssid_len = tv_data[offset++]; + + /* ssid (ssid_len bytes) */ + if (offset + ssid_len > tlv_len) + return false; + + offset += ssid_len; + + /* vid (2 bytes) */ + if (offset + 2 > tlv_len) + return false; + + offset += 2; + } + } + + /* Parse AP Radio Identifier TLV */ + if (tv[2][0]) { + uint8_t *tv_data; + uint16_t tlv_len = tlv_length(tv[2][0]); + + /* bssid (6 bytes) */ + if (tlv_len != 6) + return false; + + tv_data = (uint8_t *) tv[2][0]->data; + if (!tv_data) + return false; + } + + /* Parse WSC TLVs (containing M2) */ + while (tv[3][num]) { + uint8_t *tv_data; + uint16_t tlv_len = tlv_length(tv[3][num]); + + if (!tlv_len) + return false; + + tv_data = (uint8_t *) tv[3][num]->data; + if (!tv_data) + return false; + + if (!validate_wsc_m2(tv_data, tlv_len)) + return false; + + num++; + } + + return true; +} diff --git a/src/cmdu_validate.h b/src/cmdu_validate.h index df29878c0..681eb23cb 100644 --- a/src/cmdu_validate.h +++ b/src/cmdu_validate.h @@ -4,5 +4,6 @@ bool validate_channel_scan_request(struct cmdu_buff *cmdu, struct tlv *tv[][16]); bool validate_topology_response(struct cmdu_buff *cmdu, struct tlv *tv[][16]); +bool validate_ap_autoconfig_wsc(struct cmdu_buff *cmdu, struct tlv *tv[][16]); #endif /* CMDU_VALIDATE */ -- GitLab