diff --git a/os_if/linux/wifi_pos/src/os_if_wifi_pos.c b/os_if/linux/wifi_pos/src/os_if_wifi_pos.c index 79f4623897..0af520a2d9 100644 --- a/os_if/linux/wifi_pos/src/os_if_wifi_pos.c +++ b/os_if/linux/wifi_pos/src/os_if_wifi_pos.c @@ -85,6 +85,8 @@ static int wifi_pos_parse_req(const void *data, int len, int pid, { tAniMsgHdr *msg_hdr; struct nlattr *tb[CLD80211_ATTR_MAX + 1]; + uint32_t msg_len, id, nl_field_info_size, expected_field_info_size; + struct wifi_pos_field_info *field_info; if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) { osif_err("invalid data in request"); @@ -96,23 +98,54 @@ static int wifi_pos_parse_req(const void *data, int len, int pid, return OEM_ERR_INVALID_MESSAGE_TYPE; } - msg_hdr = (tAniMsgHdr *)nla_data(tb[CLD80211_ATTR_DATA]); - if (!msg_hdr) { - osif_err("msg_hdr null"); - return OEM_ERR_NULL_MESSAGE_HEADER; + msg_len = nla_len(tb[CLD80211_ATTR_DATA]); + if (msg_len < sizeof(*msg_hdr)) { + osif_err("Insufficient length for msg_hdr: %u", msg_len); + return OEM_ERR_INVALID_MESSAGE_LENGTH; } + msg_hdr = nla_data(tb[CLD80211_ATTR_DATA]); req->msg_type = msg_hdr->type; + + if (msg_len < sizeof(*msg_hdr) + msg_hdr->length) { + osif_err("Insufficient length for msg_hdr buffer: %u", + msg_len); + return OEM_ERR_INVALID_MESSAGE_LENGTH; + } + req->buf_len = msg_hdr->length; req->buf = (uint8_t *)&msg_hdr[1]; req->pid = pid; - if (tb[CLD80211_ATTR_META_DATA]) { - req->field_info_buf = (struct wifi_pos_field_info *) - nla_data(tb[CLD80211_ATTR_META_DATA]); - req->field_info_buf_len = nla_len(tb[CLD80211_ATTR_META_DATA]); + id = CLD80211_ATTR_META_DATA; + if (!tb[id]) + return 0; + + nl_field_info_size = nla_len(tb[id]); + if (nl_field_info_size < sizeof(*field_info)) { + osif_err("Insufficient length for field_info_buf: %u", + nl_field_info_size); + return OEM_ERR_INVALID_MESSAGE_LENGTH; } + field_info = nla_data(tb[id]); + if (!field_info->count) { + osif_debug("field_info->count is zero, ignoring META_DATA"); + return 0; + } + + expected_field_info_size = sizeof(*field_info) + + (field_info->count - 1) * sizeof(struct wifi_pos_field); + + if (nl_field_info_size < expected_field_info_size) { + osif_err("Insufficient len for total no.of %u fields", + field_info->count); + return OEM_ERR_INVALID_MESSAGE_LENGTH; + } + + req->field_info_buf = field_info; + req->field_info_buf_len = nl_field_info_size; + return 0; } #else @@ -129,6 +162,12 @@ static int wifi_pos_parse_req(struct sk_buff *skb, struct wifi_pos_req_msg *req) return OEM_ERR_NULL_MESSAGE_HEADER; } + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*msg_hdr))) { + osif_err("nlmsg_len(%d) and msg_hdr_size(%zu) mis-match", + nlh->nlmsg_len, sizeof(*msg_hdr)); + return OEM_ERR_INVALID_MESSAGE_LENGTH; + } + msg_hdr = NLMSG_DATA(nlh); if (!msg_hdr) { osif_err("Message header null"); diff --git a/umac/wifi_pos/inc/wifi_pos_api.h b/umac/wifi_pos/inc/wifi_pos_api.h index 952056cc22..9841b15433 100644 --- a/umac/wifi_pos/inc/wifi_pos_api.h +++ b/umac/wifi_pos/inc/wifi_pos_api.h @@ -32,6 +32,28 @@ struct wlan_objmgr_psoc; struct wifi_pos_driver_caps; +/** + * struct wifi_pos_field - wifi positioning field element + * @id: RTT field id + * @offset: data offset in field info buffer + * @length: length of related data in field info buffer + */ +struct wifi_pos_field { + uint32_t id; + uint32_t offset; + uint32_t length; +}; + +/** + * struct wifi_pos_field_info - wifi positioning field info buffer + * @count: number of @wifi_pos_field elements + * @fields: buffer to hold @wifi_pos_field elements + */ +struct wifi_pos_field_info { + uint32_t count; + struct wifi_pos_field fields[1]; +}; + #ifdef WIFI_POS_CONVERGED /** * enum oem_err_msg - err msg returned to user space diff --git a/umac/wifi_pos/src/wifi_pos_oem_interface_i.h b/umac/wifi_pos/src/wifi_pos_oem_interface_i.h index 5c6cb48cfe..53ace2d270 100644 --- a/umac/wifi_pos/src/wifi_pos_oem_interface_i.h +++ b/umac/wifi_pos/src/wifi_pos_oem_interface_i.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2017, 2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -43,17 +43,6 @@ #define WIFI_POS_FLAG_DFS 10 #define WIFI_POS_SET_DFS(info) (info |= (1 << WIFI_POS_FLAG_DFS)) -struct wifi_pos_field { - uint32_t id; - uint32_t offset; - uint32_t length; -}; - -struct wifi_pos_field_info { - uint32_t count; - struct wifi_pos_field fields[1]; -}; - /** * enum WMIRTT_FIELD_ID - identifies which field is being specified * @WMIRTT_FIELD_ID_oem_data_sub_type: oem data req sub type