From 452dc79c1c779ddf00ba3f995e5112a5ebfc89fa Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Tue, 17 Sep 2019 12:32:18 +0530 Subject: [PATCH] qcacld-2.0: Fix buffer overflow in HTT MSG handling If the firmware gets compromised, the values sent to the driver could result in buffer overflows. Validate HTT MSG "msg_word" to avoid buffer overflows. Change-Id: I6073029f61a358da32bcc0dcfc339d9bb7ee8218 CRs-Fixed: 2529113 --- .../qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c b/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c index 7fe1e81f8e80..5cbd4d7407a3 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c +++ b/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/HTT/htt_t2h.c @@ -177,6 +177,12 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) u_int16_t seq_num_start, seq_num_end; enum htt_rx_flush_action action; + if (adf_nbuf_len(htt_t2h_msg) < HTT_RX_FLUSH_BYTES) { + adf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + peer_id = HTT_RX_FLUSH_PEER_ID_GET(*msg_word); tid = HTT_RX_FLUSH_TID_GET(*msg_word); seq_num_start = HTT_RX_FLUSH_SEQ_NUM_START_GET(*(msg_word+1)); @@ -211,6 +217,13 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) { u_int16_t peer_id; u_int8_t tid; + int msg_len = adf_nbuf_len(htt_t2h_msg); + + if (msg_len < HTT_RX_FRAG_IND_BYTES) { + adf_print("invalid nbuff len"); + WARN_ON(1); + break; + } peer_id = HTT_RX_FRAG_IND_PEER_ID_GET(*msg_word); tid = HTT_RX_FRAG_IND_EXT_TID_GET(*msg_word); @@ -294,6 +307,12 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) u_int16_t peer_id; u_int8_t vdev_id; + if (adf_nbuf_len(htt_t2h_msg) < HTT_RX_PEER_MAP_BYTES) { + adf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + peer_id = HTT_RX_PEER_MAP_PEER_ID_GET(*msg_word); vdev_id = HTT_RX_PEER_MAP_VDEV_ID_GET(*msg_word); peer_mac_addr = htt_t2h_mac_addr_deswizzle( @@ -314,6 +333,13 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) case HTT_T2H_MSG_TYPE_PEER_UNMAP: { u_int16_t peer_id; + + if (adf_nbuf_len(htt_t2h_msg) < HTT_RX_PEER_UNMAP_BYTES) { + adf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word); if (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) { @@ -333,6 +359,12 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) enum htt_sec_type sec_type; int is_unicast; + if (adf_nbuf_len(htt_t2h_msg) < HTT_SEC_IND_BYTES) { + adf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + peer_id = HTT_SEC_IND_PEER_ID_GET(*msg_word); sec_type = HTT_SEC_IND_SEC_TYPE_GET(*msg_word); is_unicast = HTT_SEC_IND_UNICAST_GET(*msg_word); @@ -419,6 +451,12 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) int32_t htt_credit_delta; int sign, old_credit; + if (adf_nbuf_len(htt_t2h_msg) < HTT_TX_CREDIT_MSG_BYTES) { + adf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + htt_credit_delta_abs = HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word); sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1; htt_credit_delta = sign * htt_credit_delta_abs; @@ -491,7 +529,16 @@ htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg ) struct ol_txrx_vdev_t *vdev; struct ol_txrx_peer_t *peer; u_int8_t * pn_ptr; - u_int16_t peer_id = + u_int16_t peer_id; + int msg_len = adf_nbuf_len(htt_t2h_msg); + + if (msg_len < HTT_RX_OFLD_PKT_ERR_MIC_ERR_BYTES) { + adf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + peer_id = HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_GET(*(msg_word + 1)); peer = ol_txrx_peer_find_by_id(pdev->txrx_pdev, peer_id); @@ -777,6 +824,13 @@ if (adf_os_unlikely(pdev->rx_ring.rx_reset)) { u_int16_t peer_id; u_int8_t tid, pn_ie_cnt, *pn_ie=NULL; u_int16_t seq_num_start, seq_num_end; + int msg_len = adf_nbuf_len(htt_t2h_msg); + + if (msg_len < HTT_RX_PN_IND_BYTES) { + adf_print("invalid nbuff len"); + WARN_ON(1); + break; + } /*First dword */ peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word); @@ -788,6 +842,13 @@ if (adf_os_unlikely(pdev->rx_ring.rx_reset)) { seq_num_end = HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word); pn_ie_cnt = HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word); + if (msg_len - HTT_RX_PN_IND_BYTES < + pn_ie_cnt * sizeof(uint8_t)) { + adf_print("invalid pn_ie len"); + WARN_ON(1); + break; + } + msg_word++; /*Third dword*/ if (pn_ie_cnt) {