qcacmn: Add sanity check for wmi TLV length

Add sanity check for wmi TLV header length before padding/shrinking
elements in a wmi which has a variable length for its TLV structure.
Currently, the TLV length is not checked so its maximum value could
be 65535 which results in a hugh count for elements. Number of elements
is used to terminate the loop for padding/shrinking. If the number
was too large, there would be memory overflow.

Change-Id: Iea0615fc511696c6cc5dcc48a9dfff225256a52b
CRs-Fixed: 2181685
This commit is contained in:
Gurumoorthi Gnanasambandhan
2018-02-05 23:21:40 +05:30
committed by snandini
父節點 8cdcf67521
當前提交 1075366660

查看文件

@@ -507,6 +507,7 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr,
wmitlv_cmd_param_info *cmd_param_tlvs_ptr = NULL; wmitlv_cmd_param_info *cmd_param_tlvs_ptr = NULL;
A_UINT32 remaining_expected_tlvs = 0xFFFFFFFF; A_UINT32 remaining_expected_tlvs = 0xFFFFFFFF;
A_UINT32 len_wmi_cmd_struct_buf; A_UINT32 len_wmi_cmd_struct_buf;
A_UINT32 free_buf_len;
A_INT32 error = -1; A_INT32 error = -1;
/* Get the number of TLVs for this command/event */ /* Get the number of TLVs for this command/event */
@@ -569,6 +570,13 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr,
WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr));
int num_padding_bytes = 0; int num_padding_bytes = 0;
free_buf_len = param_buf_len - (buf_idx + WMI_TLV_HDR_SIZE);
if (curr_tlv_len > free_buf_len) {
wmi_tlv_print_error("%s: TLV length overflow",
__func__);
goto Error_wmitlv_check_and_pad_tlvs;
}
/* Get the attributes of the TLV with the given order in "tlv_index" */ /* Get the attributes of the TLV with the given order in "tlv_index" */
wmi_tlv_OS_MEMZERO(&attr_struct_ptr, wmi_tlv_OS_MEMZERO(&attr_struct_ptr,
sizeof(wmitlv_attributes_struc)); sizeof(wmitlv_attributes_struc));
@@ -632,6 +640,13 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr,
WMITLV_GET_TLVLEN(WMITLV_GET_HDR WMITLV_GET_TLVLEN(WMITLV_GET_HDR
(buf_ptr)); (buf_ptr));
in_tlv_len += WMI_TLV_HDR_SIZE; in_tlv_len += WMI_TLV_HDR_SIZE;
if (in_tlv_len > curr_tlv_len) {
wmi_tlv_print_error("%s: Invalid in_tlv_len=%d",
__func__,
in_tlv_len);
goto
Error_wmitlv_check_and_pad_tlvs;
}
tlv_size_diff = tlv_size_diff =
in_tlv_len - in_tlv_len -
attr_struct_ptr.tag_struct_size; attr_struct_ptr.tag_struct_size;
@@ -751,8 +766,17 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr,
/* Move subsequent TLVs by number of bytes to be padded /* Move subsequent TLVs by number of bytes to be padded
* for all elements */ * for all elements */
if (param_buf_len > if ((free_buf_len <
(buf_idx + curr_tlv_len)) { attr_struct_ptr.tag_struct_size *
num_of_elems) ||
(param_buf_len <
buf_idx + curr_tlv_len +
num_padding_bytes * num_of_elems)) {
wmi_tlv_print_error("%s: Insufficent buffer\n",
__func__);
goto
Error_wmitlv_check_and_pad_tlvs;
} else {
src_addr = src_addr =
buf_ptr + curr_tlv_len; buf_ptr + curr_tlv_len;
dst_addr = dst_addr =
@@ -772,12 +796,10 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr,
* bytes to be padded for one element and alse set * bytes to be padded for one element and alse set
* padding bytes to zero */ * padding bytes to zero */
tlv_buf_ptr = buf_ptr; tlv_buf_ptr = buf_ptr;
for (i = 0; i < num_of_elems; i++) { for (i = 0; i < num_of_elems - 1; i++) {
src_addr = src_addr =
tlv_buf_ptr + in_tlv_len; tlv_buf_ptr + in_tlv_len;
if (i != (num_of_elems - 1)) { if (i != (num_of_elems - 1)) {
/* Need not move anything for last element
* in the array */
dst_addr = dst_addr =
tlv_buf_ptr + tlv_buf_ptr +
in_tlv_len + in_tlv_len +
@@ -800,6 +822,9 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr,
attr_struct_ptr. attr_struct_ptr.
tag_struct_size; tag_struct_size;
} }
src_addr = tlv_buf_ptr + in_tlv_len;
wmi_tlv_OS_MEMZERO(src_addr,
num_padding_bytes);
/* Update the number of padding bytes to total number /* Update the number of padding bytes to total number
* of bytes padded for all elements in the array */ * of bytes padded for all elements in the array */