diff options
| author | Gurumoorthi Gnanasambandhan <gguru@codeaurora.org> | 2018-02-05 23:21:40 +0530 |
|---|---|---|
| committer | Vignesh Viswanathan <viswanat@codeaurora.org> | 2018-02-07 10:44:05 +0530 |
| commit | 9ef8683e1329596436493ff808f94451a84a1ff0 (patch) | |
| tree | 363ab171d283b218fb2fac3a4993dcf6aed66afc | |
| parent | 9a10dbd0324fa6612bd3923cc8bcba8ad3cf51f6 (diff) | |
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
| -rw-r--r-- | wmi/src/wmi_tlv_helper.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/wmi/src/wmi_tlv_helper.c b/wmi/src/wmi_tlv_helper.c index b6931f51a0fa..451a4b3d8ae8 100644 --- a/wmi/src/wmi_tlv_helper.c +++ b/wmi/src/wmi_tlv_helper.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -505,6 +505,7 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr, wmitlv_cmd_param_info *cmd_param_tlvs_ptr = NULL; A_UINT32 remaining_expected_tlvs = 0xFFFFFFFF; A_UINT32 len_wmi_cmd_struct_buf; + A_UINT32 free_buf_len; A_INT32 error = -1; /* Get the number of TLVs for this command/event */ @@ -567,6 +568,13 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr, WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); 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" */ wmi_tlv_OS_MEMZERO(&attr_struct_ptr, sizeof(wmitlv_attributes_struc)); @@ -630,6 +638,13 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr, WMITLV_GET_TLVLEN(WMITLV_GET_HDR (buf_ptr)); 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 = in_tlv_len - attr_struct_ptr.tag_struct_size; @@ -749,8 +764,17 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr, /* Move subsequent TLVs by number of bytes to be padded * for all elements */ - if (param_buf_len > - (buf_idx + curr_tlv_len)) { + if ((free_buf_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 = buf_ptr + curr_tlv_len; dst_addr = @@ -770,12 +794,10 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr, * bytes to be padded for one element and alse set * padding bytes to zero */ tlv_buf_ptr = buf_ptr; - for (i = 0; i < num_of_elems; i++) { + for (i = 0; i < num_of_elems - 1; i++) { src_addr = tlv_buf_ptr + in_tlv_len; if (i != (num_of_elems - 1)) { - /* Need not move anything for last element - * in the array */ dst_addr = tlv_buf_ptr + in_tlv_len + @@ -798,6 +820,9 @@ wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr, attr_struct_ptr. 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 * of bytes padded for all elements in the array */ |
