Merge "soc: qcom: qmi_encdec: out of bound check for input buffer"

This commit is contained in:
qctecmdr 2023-11-30 01:44:05 -08:00 • committed by Gerrit - the friendly Code Review server
commit 8da91b648e

View file

@ -427,6 +427,7 @@ static int qmi_encode(struct qmi_elem_info *ei_array, void *out_buf,
* @buf_src: Buffer containing the elements in QMI wire format.
* @elem_len: Number of elements to be decoded.
* @elem_size: Size of a single instance of the element to be decoded.
* @src_len: Source buffer length.
*
* This function decodes the "elem_len" number of elements in QMI wire format,
* each of size "elem_size" bytes from the source buffer "buf_src" and stores
@ -437,10 +438,13 @@ static int qmi_encode(struct qmi_elem_info *ei_array, void *out_buf,
* Return: The total size of the decoded data elements, in bytes.
*/
static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src,
u32 elem_len, u32 elem_size)
u32 elem_len, u32 elem_size, u32 src_len)
{
u32 i, rc = 0;
if (elem_len * elem_size > src_len)
return -EINVAL;
for (i = 0; i < elem_len; i++) {
QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, elem_size);
rc += elem_size;
@ -458,6 +462,7 @@ static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src,
* @tlv_len: Total size of the encoded inforation corresponding to
* this struct element.
* @dec_level: Depth of the nested structure from the main structure.
* @src_len: Source buffer length.
*
* This function decodes the "elem_len" number of elements in QMI wire format,
* each of size "(tlv_len/elem_len)" bytes from the source buffer "buf_src"
@ -471,16 +476,20 @@ static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src,
static int qmi_decode_struct_elem(struct qmi_elem_info *ei_array,
void *buf_dst, const void *buf_src,
u32 elem_len, u32 tlv_len,
int dec_level)
int dec_level, u32 src_len)
{
int i, rc, decoded_bytes = 0;
struct qmi_elem_info *temp_ei = ei_array;
if (tlv_len > src_len)
return -EINVAL;
for (i = 0; i < elem_len && decoded_bytes < tlv_len; i++) {
rc = qmi_decode(temp_ei->ei_array, buf_dst, buf_src,
tlv_len - decoded_bytes, dec_level);
if (rc < 0)
return rc;
buf_src = buf_src + rc;
buf_dst = buf_dst + temp_ei->elem_size;
decoded_bytes += rc;
@ -505,6 +514,7 @@ static int qmi_decode_struct_elem(struct qmi_elem_info *ei_array,
* @tlv_len: Total size of the encoded inforation corresponding to
* this string element.
* @dec_level: Depth of the string element from the main structure.
* @src_len: Source buffer length.
*
* This function decodes the string element of maximum length
* "ei_array->elem_len" from the source buffer "buf_src" and puts it into
@ -516,7 +526,7 @@ static int qmi_decode_struct_elem(struct qmi_elem_info *ei_array,
*/
static int qmi_decode_string_elem(struct qmi_elem_info *ei_array,
void *buf_dst, const void *buf_src,
u32 tlv_len, int dec_level)
u32 tlv_len, int dec_level, u32 src_len)
{
int rc;
int decoded_bytes = 0;
@ -530,7 +540,10 @@ static int qmi_decode_string_elem(struct qmi_elem_info *ei_array,
string_len_sz = temp_ei->elem_len <= U8_MAX ?
sizeof(u8) : sizeof(u16);
rc = qmi_decode_basic_elem(&string_len, buf_src,
1, string_len_sz);
1, string_len_sz, src_len);
if (rc < 0)
return rc;
decoded_bytes += rc;
}
@ -545,7 +558,11 @@ static int qmi_decode_string_elem(struct qmi_elem_info *ei_array,
}
rc = qmi_decode_basic_elem(buf_dst, buf_src + decoded_bytes,
string_len, temp_ei->elem_size);
string_len, temp_ei->elem_size,
src_len - decoded_bytes);
if (rc < 0)
return rc;
*((char *)buf_dst + string_len) = '\0';
decoded_bytes += rc;
@ -611,6 +628,9 @@ static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
if (dec_level == 1) {
tlv_pointer = buf_src;
if (decoded_bytes + TLV_TYPE_SIZE + TLV_LEN_SIZE > in_buf_len)
return -EINVAL;
QMI_ENCDEC_DECODE_TLV(&tlv_type,
&tlv_len, tlv_pointer);
buf_src += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
@ -643,7 +663,11 @@ static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
data_len_sz = temp_ei->elem_size == sizeof(u8) ?
sizeof(u8) : sizeof(u16);
rc = qmi_decode_basic_elem(&data_len_value, buf_src,
1, data_len_sz);
1, data_len_sz,
in_buf_len - decoded_bytes);
if (rc < 0)
return rc;
memcpy(buf_dst, &data_len_value, sizeof(u32));
temp_ei = temp_ei + 1;
buf_dst = out_c_struct + temp_ei->offset;
@ -670,24 +694,32 @@ static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
case QMI_SIGNED_4_BYTE_ENUM:
rc = qmi_decode_basic_elem(buf_dst, buf_src,
data_len_value,
temp_ei->elem_size);
temp_ei->elem_size,
in_buf_len - decoded_bytes);
if (rc < 0)
return rc;
UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
break;
case QMI_STRUCT:
rc = qmi_decode_struct_elem(temp_ei, buf_dst, buf_src,
data_len_value, tlv_len,
dec_level + 1);
dec_level + 1,
in_buf_len - decoded_bytes);
if (rc < 0)
return rc;
UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
break;
case QMI_STRING:
rc = qmi_decode_string_elem(temp_ei, buf_dst, buf_src,
tlv_len, dec_level);
tlv_len, dec_level,
in_buf_len - decoded_bytes);
if (rc < 0)
return rc;
UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
break;