summaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2021-08-19 23:28:23 +0300
committerKalle Valo <kvalo@codeaurora.org>2021-08-21 20:15:35 +0300
commitd6b6d1bb80beabab43aa5f4289721e6659790f3a (patch)
tree7af2c7a6f9a945c262a8a4de57779a29303b7495 /drivers/net/wireless
parent6f78f4a41ee0c348af73ed054ccff2d9c9c17cdb (diff)
downloadlinux-d6b6d1bb80beabab43aa5f4289721e6659790f3a.tar.xz
ipw2x00: Avoid field-overflowing memcpy()
In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring fields. libipw_read_qos_param_element() copies a struct libipw_info_element into a struct libipw_qos_information_element, but is actually wanting to copy into the larger struct libipw_qos_parameter_info (the contents of ac_params_record[] is later examined). Refactor the routine to perform centralized checks, and copy the entire contents directly (since the id and len members match the elementID and length members): struct libipw_info_element { u8 id; u8 len; u8 data[]; } __packed; struct libipw_qos_information_element { u8 elementID; u8 length; u8 qui[QOS_OUI_LEN]; u8 qui_type; u8 qui_subtype; u8 version; u8 ac_info; } __packed; struct libipw_qos_parameter_info { struct libipw_qos_information_element info_element; u8 reserved; struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; } __packed; Cc: Stanislav Yakovlev <stas.yakovlev@gmail.com> Cc: Kalle Valo <kvalo@codeaurora.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Jakub Kicinski <kuba@kernel.org> Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/20210819202825.3545692-2-keescook@chromium.org
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_rx.c56
1 files changed, 17 insertions, 39 deletions
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
index 5a2a723e480b..7a684b76f39b 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
@@ -927,7 +927,8 @@ static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
static int libipw_verify_qos_info(struct libipw_qos_information_element
*info_element, int sub_type)
{
-
+ if (info_element->elementID != QOS_ELEMENT_ID)
+ return -1;
if (info_element->qui_subtype != sub_type)
return -1;
if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN))
@@ -943,57 +944,34 @@ static int libipw_verify_qos_info(struct libipw_qos_information_element
/*
* Parse a QoS parameter element
*/
-static int libipw_read_qos_param_element(struct libipw_qos_parameter_info
- *element_param, struct libipw_info_element
- *info_element)
+static int libipw_read_qos_param_element(
+ struct libipw_qos_parameter_info *element_param,
+ struct libipw_info_element *info_element)
{
- int ret = 0;
- u16 size = sizeof(struct libipw_qos_parameter_info) - 2;
+ size_t size = sizeof(*element_param);
- if ((info_element == NULL) || (element_param == NULL))
+ if (!element_param || !info_element || info_element->len != size - 2)
return -1;
- if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) {
- memcpy(element_param->info_element.qui, info_element->data,
- info_element->len);
- element_param->info_element.elementID = info_element->id;
- element_param->info_element.length = info_element->len;
- } else
- ret = -1;
- if (ret == 0)
- ret = libipw_verify_qos_info(&element_param->info_element,
- QOS_OUI_PARAM_SUB_TYPE);
- return ret;
+ memcpy(element_param, info_element, size);
+ return libipw_verify_qos_info(&element_param->info_element,
+ QOS_OUI_PARAM_SUB_TYPE);
}
/*
* Parse a QoS information element
*/
-static int libipw_read_qos_info_element(struct
- libipw_qos_information_element
- *element_info, struct libipw_info_element
- *info_element)
+static int libipw_read_qos_info_element(
+ struct libipw_qos_information_element *element_info,
+ struct libipw_info_element *info_element)
{
- int ret = 0;
- u16 size = sizeof(struct libipw_qos_information_element) - 2;
+ size_t size = sizeof(struct libipw_qos_information_element) - 2;
- if (element_info == NULL)
+ if (!element_info || !info_element || info_element->len != size - 2)
return -1;
- if (info_element == NULL)
- return -1;
-
- if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) {
- memcpy(element_info->qui, info_element->data,
- info_element->len);
- element_info->elementID = info_element->id;
- element_info->length = info_element->len;
- } else
- ret = -1;
- if (ret == 0)
- ret = libipw_verify_qos_info(element_info,
- QOS_OUI_INFO_SUB_TYPE);
- return ret;
+ memcpy(element_info, info_element, size);
+ return libipw_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE);
}
/*