qcacld-2.0: Fix buffer overflow in process_rx_info etc
Currently data in "pl_tgt_hdr" is used directly from firmware without any length check which may cause buffer over-read. To address this issue add length check before accessing data offset Change-Id: Ia968806b765bb41e39395e15fcc3c8f880ae7335 CRs-Fixed: 2240226
This commit is contained in:
parent
cd7a863e1d
commit
d58f9255b0
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
|
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
|
||||||
*
|
*
|
||||||
|
@ -546,11 +546,33 @@ process_rx_info(void *pdev, void *data)
|
||||||
struct ath_pktlog_hdr pl_hdr;
|
struct ath_pktlog_hdr pl_hdr;
|
||||||
size_t log_size;
|
size_t log_size;
|
||||||
uint32_t *pl_tgt_hdr;
|
uint32_t *pl_tgt_hdr;
|
||||||
|
struct ol_fw_data *fw_data;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
if (!pdev) {
|
if (!pdev) {
|
||||||
printk("Invalid pdev in %s", __func__);
|
printk("Invalid pdev in %s", __func__);
|
||||||
return A_ERROR;
|
return A_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fw_data = (struct ol_fw_data *)data;
|
||||||
|
len = fw_data->len;
|
||||||
|
if (len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_TIMESTAMP_OFFSET + 1))) {
|
||||||
|
adf_os_print("Invalid msdu len in %s\n", __func__);
|
||||||
|
adf_os_assert(0);
|
||||||
|
return A_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = fw_data->data;
|
||||||
|
|
||||||
pl_dev = ((struct ol_txrx_pdev_t *) pdev)->pl_dev;
|
pl_dev = ((struct ol_txrx_pdev_t *) pdev)->pl_dev;
|
||||||
pl_info = pl_dev->pl_info;
|
pl_info = pl_dev->pl_info;
|
||||||
pl_tgt_hdr = (uint32_t *)data;
|
pl_tgt_hdr = (uint32_t *)data;
|
||||||
|
@ -567,6 +589,12 @@ process_rx_info(void *pdev, void *data)
|
||||||
ATH_PKTLOG_HDR_SIZE_MASK) >>
|
ATH_PKTLOG_HDR_SIZE_MASK) >>
|
||||||
ATH_PKTLOG_HDR_SIZE_SHIFT;
|
ATH_PKTLOG_HDR_SIZE_SHIFT;
|
||||||
pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
|
pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
|
||||||
|
|
||||||
|
if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
|
||||||
|
adf_os_assert(0);
|
||||||
|
return A_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
log_size = pl_hdr.size;
|
log_size = pl_hdr.size;
|
||||||
rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
|
rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
|
||||||
log_size, &pl_hdr);
|
log_size, &pl_hdr);
|
||||||
|
@ -593,6 +621,8 @@ process_rate_find(void *pdev, void *data)
|
||||||
*/
|
*/
|
||||||
struct ath_pktlog_rc_find rcf_log;
|
struct ath_pktlog_rc_find rcf_log;
|
||||||
uint32_t *pl_tgt_hdr;
|
uint32_t *pl_tgt_hdr;
|
||||||
|
struct ol_fw_data *fw_data;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
if (!pdev) {
|
if (!pdev) {
|
||||||
adf_os_print("Invalid pdev in %s\n", __func__);
|
adf_os_print("Invalid pdev in %s\n", __func__);
|
||||||
|
@ -603,6 +633,25 @@ process_rate_find(void *pdev, void *data)
|
||||||
return A_ERROR;
|
return A_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fw_data = (struct ol_fw_data *)data;
|
||||||
|
len = fw_data->len;
|
||||||
|
if (len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_TIMESTAMP_OFFSET + 1))) {
|
||||||
|
adf_os_print("Invalid msdu len in %s\n", __func__);
|
||||||
|
adf_os_assert(0);
|
||||||
|
return A_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = fw_data->data;
|
||||||
|
|
||||||
pl_tgt_hdr = (uint32_t *)data;
|
pl_tgt_hdr = (uint32_t *)data;
|
||||||
/*
|
/*
|
||||||
* Makes the short words (16 bits) portable b/w little endian
|
* Makes the short words (16 bits) portable b/w little endian
|
||||||
|
@ -621,6 +670,12 @@ process_rate_find(void *pdev, void *data)
|
||||||
ATH_PKTLOG_HDR_SIZE_MASK) >>
|
ATH_PKTLOG_HDR_SIZE_MASK) >>
|
||||||
ATH_PKTLOG_HDR_SIZE_SHIFT;
|
ATH_PKTLOG_HDR_SIZE_SHIFT;
|
||||||
pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
|
pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
|
||||||
|
|
||||||
|
if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
|
||||||
|
adf_os_assert(0);
|
||||||
|
return A_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
pl_dev = ((struct ol_txrx_pdev_t *) pdev)->pl_dev;
|
pl_dev = ((struct ol_txrx_pdev_t *) pdev)->pl_dev;
|
||||||
pl_info = pl_dev->pl_info;
|
pl_info = pl_dev->pl_info;
|
||||||
log_size = pl_hdr.size;
|
log_size = pl_hdr.size;
|
||||||
|
@ -643,6 +698,8 @@ process_rate_update(void *pdev, void *data)
|
||||||
struct ath_pktlog_info *pl_info;
|
struct ath_pktlog_info *pl_info;
|
||||||
struct ath_pktlog_rc_update rcu_log;
|
struct ath_pktlog_rc_update rcu_log;
|
||||||
uint32_t *pl_tgt_hdr;
|
uint32_t *pl_tgt_hdr;
|
||||||
|
struct ol_fw_data *fw_data;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
if (!pdev) {
|
if (!pdev) {
|
||||||
printk("Invalid pdev in %s\n", __func__);
|
printk("Invalid pdev in %s\n", __func__);
|
||||||
|
@ -652,6 +709,26 @@ process_rate_update(void *pdev, void *data)
|
||||||
printk("Invalid data in %s\n", __func__);
|
printk("Invalid data in %s\n", __func__);
|
||||||
return A_ERROR;
|
return A_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fw_data = (struct ol_fw_data *)data;
|
||||||
|
len = fw_data->len;
|
||||||
|
if (len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
|
||||||
|
len < (sizeof(uint32_t) *
|
||||||
|
(ATH_PKTLOG_HDR_TIMESTAMP_OFFSET + 1))) {
|
||||||
|
adf_os_print("Invalid msdu len in %s\n", __func__);
|
||||||
|
adf_os_assert(0);
|
||||||
|
return A_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = fw_data->data;
|
||||||
|
|
||||||
pl_tgt_hdr = (uint32_t *)data;
|
pl_tgt_hdr = (uint32_t *)data;
|
||||||
/*
|
/*
|
||||||
* Makes the short words (16 bits) portable b/w little endian
|
* Makes the short words (16 bits) portable b/w little endian
|
||||||
|
@ -670,6 +747,12 @@ process_rate_update(void *pdev, void *data)
|
||||||
ATH_PKTLOG_HDR_SIZE_MASK) >>
|
ATH_PKTLOG_HDR_SIZE_MASK) >>
|
||||||
ATH_PKTLOG_HDR_SIZE_SHIFT;
|
ATH_PKTLOG_HDR_SIZE_SHIFT;
|
||||||
pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
|
pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
|
||||||
|
|
||||||
|
if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
|
||||||
|
adf_os_assert(0);
|
||||||
|
return A_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
pl_dev = ((struct ol_txrx_pdev_t *) pdev)->pl_dev;
|
pl_dev = ((struct ol_txrx_pdev_t *) pdev)->pl_dev;
|
||||||
log_size = pl_hdr.size;
|
log_size = pl_hdr.size;
|
||||||
pl_info = pl_dev->pl_info;
|
pl_info = pl_dev->pl_info;
|
||||||
|
|
Loading…
Reference in New Issue