From f944869734991699e3ba570aba1a96a4f00f6feb Mon Sep 17 00:00:00 2001
From: Filip Matusiak <filip.matusiak@iopsys.eu>
Date: Wed, 23 Feb 2022 16:59:04 +0100
Subject: [PATCH] map-agent: Sanitize ap autoconfig search CMDU
---
src/agent_map.c | 15 +---
src/cmdu_validate.c | 162 ++++++++++++++++++++++++++++++++++++++++++++
src/cmdu_validate.h | 1 +
3 files changed, 166 insertions(+), 12 deletions(-)
diff --git a/src/agent_map.c b/src/agent_map.c
index 23c97562d..882d77607 100644
--- a/src/agent_map.c
+++ b/src/agent_map.c
@@ -820,22 +820,13 @@ int handle_ap_autoconfig_search(void *agent, struct cmdu_buff *rx_cmdu)
struct agent *a = (struct agent *) agent;
bool cntlr = false;
int i;
- struct tlv_policy a_policy[] = {
- [0] = { .type = TLV_TYPE_AL_MAC_ADDRESS_TYPE, .present = TLV_PRESENT_ONE },
- [1] = { .type = TLV_TYPE_SEARCHED_ROLE, .present = TLV_PRESENT_ONE },
- [2] = { .type = TLV_TYPE_AUTOCONFIG_FREQ_BAND, .present = TLV_PRESENT_ONE },
- [3] = { .type = MAP_TLV_SUPPORTED_SERVICE, .present = TLV_PRESENT_ONE },
- [4] = { .type = MAP_TLV_SEARCHED_SERVICE, .present = TLV_PRESENT_ONE },
- [5] = { .type = MAP_TLV_MULTIAP_PROFILE, .present = TLV_PRESENT_ONE }
- };
uint8_t aladdr_origin[6] = {0};
struct tlv *tv[6][16] = {0};
- cmdu_parse_tlvs(rx_cmdu, tv, a_policy, 6);
-
- if (!tv[0][0] || !tv[1][0] || !tv[2][0] || !tv[3][0] || !tv[4][0]
- || !tv[5][0])
+ if (!validate_ap_autoconfig_search(rx_cmdu, tv)) {
+ dbg("cmdu validation: [AP_AUTOCONFIG_SEARCH] failed\n");
return -1;
+ }
memcpy(aladdr_origin, tv[0][0]->data, 6);
if (hwaddr_is_zero(aladdr_origin)) {
diff --git a/src/cmdu_validate.c b/src/cmdu_validate.c
index b58bafe0d..9e0bf4aab 100644
--- a/src/cmdu_validate.c
+++ b/src/cmdu_validate.c
@@ -373,3 +373,165 @@ bool validate_ap_autoconfig_wsc(struct cmdu_buff *cmdu, struct tlv *tv[][16])
return true;
}
+
+bool validate_ap_autoconfig_search(struct cmdu_buff *cmdu, struct tlv *tv[][16])
+{
+ struct tlv_policy a_policy[] = {
+ [0] = { .type = TLV_TYPE_AL_MAC_ADDRESS_TYPE,
+ .present = TLV_PRESENT_ONE,
+ .minlen = 6, /* macaddr */
+ .maxlen = 6
+ },
+ [1] = { .type = TLV_TYPE_SEARCHED_ROLE,
+ .present = TLV_PRESENT_ONE,
+ .minlen = 1, /* tlv_searched_role */
+ .maxlen = 1
+ },
+ [2] = { .type = TLV_TYPE_AUTOCONFIG_FREQ_BAND,
+ .present = TLV_PRESENT_ONE,
+ .minlen = 1, /* tlv_autoconfig_band */
+ .maxlen = 1
+ },
+ [3] = { .type = MAP_TLV_SUPPORTED_SERVICE,
+ .present = TLV_PRESENT_ONE,
+ .minlen = 1, /* num of services */
+ },
+ [4] = { .type = MAP_TLV_SEARCHED_SERVICE,
+ .present = TLV_PRESENT_ONE,
+ .minlen = 1, /* num of services */
+ },
+ [5] = { .type = MAP_TLV_MULTIAP_PROFILE,
+ .present = TLV_PRESENT_ONE,
+ .minlen = 1, /* tlv_map_profile */
+ .maxlen = 1
+ }
+ };
+ //int num = 0;
+ int ret;
+
+ trace("%s |" MACFMT "|CMDU: ap autoconfig search\n",
+ __func__, MAC2STR(cmdu->origin));
+
+ ret = cmdu_parse_tlvs(cmdu, tv, a_policy, 6);
+ if (ret) {
+ dbg("%s: parse_tlv failed\n", __func__);
+ return false;
+ }
+
+ if (!tv[0][0] || !tv[1][0] || !tv[2][0] || !tv[5][0]) {
+ dbg("%s: Missing one or more mandatory TLV!\n", __func__);
+ return false;
+ }
+
+ /* Parse 1905.1 AL MAC address type TLV */
+ if (tv[0][0]) {
+ uint8_t *tv_data;
+ uint16_t tlv_len = tlv_length(tv[0][0]);
+
+ /* macaddr (6 bytes) */
+ if (tlv_len != 6)
+ return false;
+
+ tv_data = (uint8_t *) tv[0][0]->data;
+ if (!tv_data)
+ return false;
+ }
+
+ /* Parse SearchedRole TLV */
+ if (tv[1][0]) {
+ struct tlv_searched_role *tlv;
+ uint16_t tlv_len = tlv_length(tv[1][0]);
+
+ /* role (1 byte) */
+ if (tlv_len != sizeof(struct tlv_searched_role))
+ return false;
+
+ tlv = (struct tlv_searched_role *)tv[1][0]->data;
+ if (!tlv)
+ return false;
+ }
+
+ /* Parse AutoconfigFreqBand TLV */
+ if (tv[2][0]) {
+ struct tlv_autoconfig_band *tlv;
+ uint16_t tlv_len = tlv_length(tv[2][0]);
+
+ /* band (1 byte) */
+ if (tlv_len != sizeof(struct tlv_autoconfig_band))
+ return false;
+
+ tlv = (struct tlv_autoconfig_band *)tv[2][0]->data;
+ if (!tlv)
+ return false;
+ }
+
+ /* Parse SupportedService TLV */
+ if (tv[3][0]) {
+ uint8_t *tv_data;
+ uint8_t num_services;
+ int offset = 0;
+ uint16_t tlv_len = tlv_length(tv[3][0]);
+
+ if (tlv_len < 1)
+ return false;
+
+ tv_data = (uint8_t *) tv[3][0]->data;
+ if (!tv_data)
+ return false;
+
+ /* num_services (1 byte) */
+ if (offset + 1 > tlv_len)
+ return false;
+
+ num_services = tv_data[offset];
+
+ offset += 1;
+
+ /* services (num_services bytes) */
+ if (offset + num_services > tlv_len)
+ return false;
+ }
+
+ /* Parse SearchedService TLV */
+ if (tv[4][0]) {
+ uint8_t *tv_data;
+ uint8_t num_services;
+ int offset = 0;
+ uint16_t tlv_len = tlv_length(tv[4][0]);
+
+ if (tlv_len < 1)
+ return false;
+
+ tv_data = (uint8_t *) tv[4][0]->data;
+ if (!tv_data)
+ return false;
+
+ /* num_services (1 byte) */
+ if (offset + 1 > tlv_len)
+ return false;
+
+ num_services = tv_data[offset];
+
+ offset += 1;
+
+ /* services (num_services bytes) */
+ if (offset + num_services > tlv_len)
+ return false;
+ }
+
+ /* Parse MultiAP Profile TLV */
+ if (tv[5][0]) {
+ struct tlv_map_profile *tlv;
+ uint16_t tlv_len = tlv_length(tv[5][0]);
+
+ /* profile (1 byte) */
+ if (tlv_len != sizeof(struct tlv_map_profile))
+ return false;
+
+ tlv = (struct tlv_map_profile *)tv[5][0]->data;
+ if (!tlv)
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/cmdu_validate.h b/src/cmdu_validate.h
index 681eb23cb..26a0acc89 100644
--- a/src/cmdu_validate.h
+++ b/src/cmdu_validate.h
@@ -5,5 +5,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]);
+bool validate_ap_autoconfig_search(struct cmdu_buff *cmdu, struct tlv *tv[][16]);
#endif /* CMDU_VALIDATE */
--
GitLab