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