From b2f597882ff019c1edd492c751056112c30ab125 Mon Sep 17 00:00:00 2001
From: Sreenath Sharma <sreenats@broadcom.com>
Date: Fri, 30 Oct 2015 17:25:38 +0530
Subject: [PATCH] net: wireless: bcmdhd: Ensure ring memory reading doesn't
 exceed boundary

There can be cases were the PCIe bus is in invalid state and during this
time all reads will return all ones. During this time the number of items
to be read will be junk value causing read exceeding the boundary.

To avoid this problem, check for improper length and return NULL, so that
caller will not read further.

Bug: 25397008

Change-Id: I6ea2c0c6faa708abe8e167dd899be2427c097d7a
---
 drivers/net/wireless/bcmdhd/dhd_msgbuf.c | 28 +++++++++++++++++-------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/bcmdhd/dhd_msgbuf.c b/drivers/net/wireless/bcmdhd/dhd_msgbuf.c
index 08d4026923ac..ae875dc5f4b3 100644
--- a/drivers/net/wireless/bcmdhd/dhd_msgbuf.c
+++ b/drivers/net/wireless/bcmdhd/dhd_msgbuf.c
@@ -3345,6 +3345,7 @@ prot_get_src_addr(dhd_pub_t *dhd, msgbuf_ring_t * ring, uint16* available_len)
 	uint16 w_ptr;
 	uint16 r_ptr;
 	uint16 depth;
+	uint16 items;
 	void* ret_addr = NULL;
 	uint16 d2h_w_index = 0;
 
@@ -3366,25 +3367,36 @@ prot_get_src_addr(dhd_pub_t *dhd, msgbuf_ring_t * ring, uint16* available_len)
 	depth = ring->ringmem->max_item;
 
 	/* check for avail space */
-	*available_len = READ_AVAIL_SPACE(w_ptr, r_ptr, depth);
-	if (*available_len == 0)
+	items = READ_AVAIL_SPACE(w_ptr, r_ptr, depth);
+	if (items == 0) {
+		*available_len = 0;
 		return NULL;
+	}
 
-	ASSERT(*available_len <= ring->ringmem->max_item);
+	ASSERT(items <= ring->ringmem->max_item);
+	if (items > ring->ringmem->max_item) {
+		DHD_ERROR(("%s: ring:%p, ring->name:%s, items:%d\n", __FUNCTION__,
+			ring, ring->name, items));
+		DHD_INFO(("%s: w_offset:%d, r_offset:%d, max_item:%d\n", __FUNCTION__,
+			ring->ringstate->w_offset, ring->ringstate->r_offset, ring->ringmem->max_item));
+		DHD_INFO(("%s: dhd->busstate:%d, bus->suspended:%d, bus->wait_for_d3_ack:%d\n",
+			__FUNCTION__, dhd->busstate, dhd->bus->suspended, dhd->bus->wait_for_d3_ack));
+
+		*available_len = 0;
+		return NULL;
+	}
 
 	/* if space available, calculate address to be read */
 	ret_addr = (char*)ring->ring_base.va + (r_ptr * ring->ringmem->len_items);
 
 	/* update read pointer */
-	if ((ring->ringstate->r_offset + *available_len) >= ring->ringmem->max_item)
+	if ((ring->ringstate->r_offset + items) >= ring->ringmem->max_item)
 		ring->ringstate->r_offset = 0;
 	else
-		ring->ringstate->r_offset += *available_len;
-
-	ASSERT(ring->ringstate->r_offset < ring->ringmem->max_item);
+		ring->ringstate->r_offset += items;
 
 	/* convert index to bytes */
-	*available_len = *available_len * ring->ringmem->len_items;
+	*available_len = items * ring->ringmem->len_items;
 
 	/* return read address */
 	return ret_addr;
-- 
GitLab