diff options
| author | Tiger Yu <tfyu@codeaurora.org> | 2019-04-02 17:09:18 +0800 |
|---|---|---|
| committer | Tiger Yu <tfyu@codeaurora.org> | 2019-04-02 17:12:07 +0800 |
| commit | 203db8efc8e285d9c3a417a693fa424a7daa3a72 (patch) | |
| tree | 3dbb479d6d4ca69bb7cf10c0fab6b9bbaebed83d | |
| parent | db2e29267dc9a93d36ccd873782617bf4822d2fd (diff) | |
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
| -rw-r--r-- | CORE/UTILS/PKTLOG/pktlog_internal.c | 85 |
1 files changed, 84 insertions, 1 deletions
diff --git a/CORE/UTILS/PKTLOG/pktlog_internal.c b/CORE/UTILS/PKTLOG/pktlog_internal.c index 689204978da6..2db9e9f685ff 100644 --- a/CORE/UTILS/PKTLOG/pktlog_internal.c +++ b/CORE/UTILS/PKTLOG/pktlog_internal.c @@ -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. * @@ -546,11 +546,33 @@ process_rx_info(void *pdev, void *data) struct ath_pktlog_hdr pl_hdr; size_t log_size; uint32_t *pl_tgt_hdr; + struct ol_fw_data *fw_data; + uint32_t len; if (!pdev) { printk("Invalid pdev in %s", __func__); 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_info = pl_dev->pl_info; 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_SHIFT; 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; rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr); @@ -593,6 +621,8 @@ process_rate_find(void *pdev, void *data) */ struct ath_pktlog_rc_find rcf_log; uint32_t *pl_tgt_hdr; + struct ol_fw_data *fw_data; + uint32_t len; if (!pdev) { adf_os_print("Invalid pdev in %s\n", __func__); @@ -603,6 +633,25 @@ process_rate_find(void *pdev, void *data) 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; /* * 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_SHIFT; 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_info = pl_dev->pl_info; 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_rc_update rcu_log; uint32_t *pl_tgt_hdr; + struct ol_fw_data *fw_data; + uint32_t len; if (!pdev) { 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__); 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; /* * 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_SHIFT; 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; log_size = pl_hdr.size; pl_info = pl_dev->pl_info; |
