forked from rubenslte/android_kernel_samsung_msm8226
lib: qmi: Add check to avoid out of bound memory access
If QMI clients pass an invalid maximum message length parameter, the QMI message encode operation may perform an out of bound encode buffer access. Add a check in the QMI message encode operation to avoid out of bound buffer access. CRs-Fixed: 437329 Change-Id: I9d16078fade8160f327a8a77aea6c2a8e66b3127 Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
This commit is contained in:
+28
-8
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
static int _qmi_kernel_encode(struct elem_info *ei_array,
|
||||
void *out_buf, void *in_c_struct,
|
||||
int enc_level);
|
||||
uint32_t out_buf_len, int enc_level);
|
||||
|
||||
static int _qmi_kernel_decode(struct elem_info *ei_array,
|
||||
void *out_c_struct,
|
||||
@@ -114,7 +114,7 @@ int qmi_kernel_encode(struct msg_desc *desc,
|
||||
return -ETOOSMALL;
|
||||
|
||||
return _qmi_kernel_encode(desc->ei_array, out_buf,
|
||||
in_c_struct, enc_level);
|
||||
in_c_struct, out_buf_len, enc_level);
|
||||
}
|
||||
EXPORT_SYMBOL(qmi_kernel_encode);
|
||||
|
||||
@@ -152,6 +152,7 @@ static int qmi_encode_basic_elem(void *buf_dst, void *buf_src,
|
||||
* @buf_dst: Buffer to store the encoded information.
|
||||
* @buf_src: Buffer containing the elements to be encoded.
|
||||
* @elem_len: Number of elements, in the buf_src, to be encoded.
|
||||
* @out_buf_len: Available space in the encode buffer.
|
||||
* @enc_level: Depth of the nested structure from the main structure.
|
||||
*
|
||||
* @return: Mumber of bytes of encoded information, on success.
|
||||
@@ -165,14 +166,16 @@ static int qmi_encode_basic_elem(void *buf_dst, void *buf_src,
|
||||
*/
|
||||
static int qmi_encode_struct_elem(struct elem_info *ei_array,
|
||||
void *buf_dst, void *buf_src,
|
||||
uint32_t elem_len, int enc_level)
|
||||
uint32_t elem_len, uint32_t out_buf_len,
|
||||
int enc_level)
|
||||
{
|
||||
int i, rc, encoded_bytes = 0;
|
||||
struct elem_info *temp_ei = ei_array;
|
||||
|
||||
for (i = 0; i < elem_len; i++) {
|
||||
rc = _qmi_kernel_encode(temp_ei->ei_array,
|
||||
buf_dst, buf_src, enc_level);
|
||||
rc = _qmi_kernel_encode(temp_ei->ei_array, buf_dst, buf_src,
|
||||
(out_buf_len - encoded_bytes),
|
||||
enc_level);
|
||||
if (rc < 0) {
|
||||
pr_err("%s: STRUCT Encode failure\n", __func__);
|
||||
return rc;
|
||||
@@ -214,6 +217,7 @@ static struct elem_info *skip_to_next_elem(struct elem_info *ei_array)
|
||||
* @ei_array: Struct info array describing the structure to be encoded.
|
||||
* @out_buf: Buffer to hold the encoded QMI message.
|
||||
* @in_c_struct: Pointer to the C structure to be encoded.
|
||||
* @out_buf_len: Available space in the encode buffer.
|
||||
* @enc_level: Encode level to indicate the depth of the nested structure,
|
||||
* within the main structure, being encoded.
|
||||
*
|
||||
@@ -222,7 +226,7 @@ static struct elem_info *skip_to_next_elem(struct elem_info *ei_array)
|
||||
*/
|
||||
static int _qmi_kernel_encode(struct elem_info *ei_array,
|
||||
void *out_buf, void *in_c_struct,
|
||||
int enc_level)
|
||||
uint32_t out_buf_len, int enc_level)
|
||||
{
|
||||
struct elem_info *temp_ei = ei_array;
|
||||
uint8_t opt_flag_value = 0;
|
||||
@@ -268,6 +272,13 @@ static int _qmi_kernel_encode(struct elem_info *ei_array,
|
||||
memcpy(&data_len_value, buf_src, temp_ei->elem_size);
|
||||
data_len_sz = temp_ei->elem_size == sizeof(uint8_t) ?
|
||||
sizeof(uint8_t) : sizeof(uint16_t);
|
||||
/* Check to avoid out of range buffer access */
|
||||
if ((data_len_sz + encoded_bytes + TLV_LEN_SIZE +
|
||||
TLV_TYPE_SIZE) > out_buf_len) {
|
||||
pr_err("%s: Too Small Buffer @DATA_LEN\n",
|
||||
__func__);
|
||||
return -ETOOSMALL;
|
||||
}
|
||||
rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
|
||||
1, data_len_sz);
|
||||
if (data_len_value) {
|
||||
@@ -285,6 +296,14 @@ static int _qmi_kernel_encode(struct elem_info *ei_array,
|
||||
case QMI_UNSIGNED_8_BYTE:
|
||||
case QMI_SIGNED_2_BYTE_ENUM:
|
||||
case QMI_SIGNED_4_BYTE_ENUM:
|
||||
/* Check to avoid out of range buffer access */
|
||||
if (((data_len_value * temp_ei->elem_size) +
|
||||
encoded_bytes + TLV_LEN_SIZE + TLV_TYPE_SIZE) >
|
||||
out_buf_len) {
|
||||
pr_err("%s: Too Small Buffer @data_type:%d\n",
|
||||
__func__, temp_ei->data_type);
|
||||
return -ETOOSMALL;
|
||||
}
|
||||
rc = qmi_encode_basic_elem(buf_dst, buf_src,
|
||||
data_len_value, temp_ei->elem_size);
|
||||
QMI_ENCODE_LOG_ELEM(enc_level, data_len_value,
|
||||
@@ -295,7 +314,8 @@ static int _qmi_kernel_encode(struct elem_info *ei_array,
|
||||
|
||||
case QMI_STRUCT:
|
||||
rc = qmi_encode_struct_elem(temp_ei, buf_dst, buf_src,
|
||||
data_len_value, (enc_level + 1));
|
||||
data_len_value, (out_buf_len - encoded_bytes),
|
||||
(enc_level + 1));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
|
||||
|
||||
Reference in New Issue
Block a user