--- zzzz-none-000/linux-5.4.213/drivers/soc/qcom/qmi_encdec.c 2022-09-15 10:04:56.000000000 +0000 +++ alder-5690pro-762/linux-5.4.213/drivers/soc/qcom/qmi_encdec.c 2024-08-14 09:02:08.000000000 +0000 @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2017, 2019 The Linux Foundation. All rights reserved. * Copyright (C) 2017 Linaro Ltd. */ #include @@ -25,14 +25,38 @@ #define QMI_ENCDEC_ENCODE_N_BYTES(p_dst, p_src, size) \ do { \ + u16 *var16; \ + u32 *var32; \ + u64 *var64; \ + var16 = (u16 *) p_dst; \ + var32 = (u32 *) p_dst; \ + var64 = (u64 *) p_dst; \ memcpy(p_dst, p_src, size); \ + if (size == 2) \ + *var16 = cpu_to_le16(*var16); \ + if (size == 4) \ + *var32 = cpu_to_le32(*var32); \ + if (size == 8) \ + *var64 = cpu_to_le64(*var64); \ p_dst = (u8 *)p_dst + size; \ p_src = (u8 *)p_src + size; \ } while (0) #define QMI_ENCDEC_DECODE_N_BYTES(p_dst, p_src, size) \ do { \ + u16 *var16; \ + u32 *var32; \ + u64 *var64; \ + var16 = (u16 *) p_dst; \ + var32 = (u32 *) p_dst; \ + var64 = (u64 *) p_dst; \ memcpy(p_dst, p_src, size); \ + if (size == 2) \ + *var16 = le16_to_cpu(*var16); \ + if (size == 4) \ + *var32 = le32_to_cpu(*var32); \ + if (size == 8) \ + *var64 = le64_to_cpu(*var64); \ p_dst = (u8 *)p_dst + size; \ p_src = (u8 *)p_src + size; \ } while (0) @@ -304,6 +328,9 @@ const void *buf_src; int encode_tlv = 0; int rc; +#if IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) + char *d; +#endif if (!ei_array) return 0; @@ -338,7 +365,19 @@ break; case QMI_DATA_LEN: - memcpy(&data_len_value, buf_src, temp_ei->elem_size); + memcpy(&data_len_value, buf_src, sizeof(u32)); +#if IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) + d = (char *)&data_len_value; + if (temp_ei->elem_size == 1) { + d[0] = d[3]; + d[1] = d[2] = d[3] = 0; + } + if (temp_ei->elem_size == 2) { + d[0] = d[2]; + d[1] = d[3]; + d[2] = d[3] = 0; + } +#endif data_len_sz = temp_ei->elem_size == sizeof(u8) ? sizeof(u8) : sizeof(u16); /* Check to avoid out of range buffer access */ @@ -357,6 +396,10 @@ temp_ei = skip_to_next_elem(temp_ei, enc_level); else encode_tlv = 0; + +#if IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) + data_len_value = (u32)*(u32 *)(buf_src); +#endif break; case QMI_UNSIGNED_1_BYTE: @@ -427,6 +470,7 @@ * @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 +481,13 @@ * 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 +505,7 @@ * @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 +519,20 @@ 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 +557,7 @@ * @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,12 +569,12 @@ */ 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; - u32 string_len = 0; - u32 string_len_sz = 0; + u16 string_len = 0; + u16 string_len_sz = 0; struct qmi_elem_info *temp_ei = ei_array; if (dec_level == 1) { @@ -530,12 +583,18 @@ 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; + + string_len = le16_to_cpu(string_len); decoded_bytes += rc; } - if (string_len > temp_ei->elem_len) { - pr_err("%s: String len %d > Max Len %d\n", + string_len = le16_to_cpu(string_len); + + if (string_len >= temp_ei->elem_len) { + pr_err("%s: String len %d >= Max Len %d\n", __func__, string_len, temp_ei->elem_len); return -ETOOSMALL; } else if (string_len > tlv_len) { @@ -545,7 +604,11 @@ } 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; @@ -604,6 +667,9 @@ u32 decoded_bytes = 0; const void *buf_src = in_buf; int rc; +#if IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) + char *d; +#endif while (decoded_bytes < in_buf_len) { if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI) @@ -611,6 +677,9 @@ 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); @@ -640,10 +709,27 @@ } if (temp_ei->data_type == QMI_DATA_LEN) { + data_len_value = 0; 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; + +#if IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) + d = (char *)&data_len_value; + if (temp_ei->elem_size == 1) { + d[3] = d[0]; + d[0] = d[1] = d[2] = 0; + } + if (temp_ei->elem_size == 2) { + d[2] = d[0]; + d[3] = d[1]; + d[0] = d[1] = 0; + } +#endif memcpy(buf_dst, &data_len_value, sizeof(u32)); temp_ei = temp_ei + 1; buf_dst = out_c_struct + temp_ei->offset; @@ -670,24 +756,32 @@ 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; @@ -746,9 +840,9 @@ hdr = msg; hdr->type = type; - hdr->txn_id = txn_id; - hdr->msg_id = msg_id; - hdr->msg_len = msglen; + hdr->txn_id = cpu_to_le16(txn_id); + hdr->msg_id = cpu_to_le16(msg_id); + hdr->msg_len = cpu_to_le16(msglen); *len = sizeof(*hdr) + msglen;