From 0008879d137ab1cbd32923dca903cd4ff4781f2a Mon Sep 17 00:00:00 2001 From: Pragaspathi Thilagaraj Date: Thu, 29 Mar 2018 18:43:35 +0530 Subject: [PATCH] qcacld-3.0: Fix OOB write in wma_unified_debug_print_event_handler The routine wma_unified_debug_print_event_handler logs the data from debug print event handler. The param event data from firmware is copied to a destination buffer .If the maximum size of the data exceeds or equals BIG_ENDIAN_MAX_DEBUG_BUF for big endian hosts then possible OOB write will occur in wma_unified_debug_print_event_handler. For other hosts, OOB read could occur if datalen exceeds maximum firmware message size WMI_SVC_MAX_SIZE. Add check to validate datalen doesnot exceed the maximum firmware msg size WMI_SVC_MAX_SIZE. Return failure if it exceeds. Add check to ensure datalen doesnot exceed or equal the maximum buffer length value for big endian hosts BIG_ENDIAN_MAX_DEBUG_BUF. Invoke strlcpy instead of memcpy to ensure the string is null terminated before printed. Change-Id: I45943ae76d8fcf7b53e1f064c462d01cd6d00dcf CRs-Fixed: 2211133 --- core/wma/src/wma_utils.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index c68bd197d8..8e1a2dd804 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -3525,31 +3525,43 @@ int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap, WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf; uint8_t *data; uint32_t datalen; + char dbgbuf[WMI_SVC_MSG_MAX_SIZE] = { 0 }; param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap; - if (!param_buf) { + if (!param_buf || !param_buf->data) { WMA_LOGE("Get NULL point message from FW"); return -ENOMEM; } data = param_buf->data; datalen = param_buf->num_data; + if (datalen > WMI_SVC_MSG_MAX_SIZE) { + WMA_LOGE("Received data len %d exceeds max value %d", + datalen, WMI_SVC_MSG_MAX_SIZE); + return QDF_STATUS_E_FAILURE; + } #ifdef BIG_ENDIAN_HOST { - if (datalen > BIG_ENDIAN_MAX_DEBUG_BUF) { + if (datalen >= BIG_ENDIAN_MAX_DEBUG_BUF) { WMA_LOGE("%s Invalid data len %d, limiting to max", __func__, datalen); - datalen = BIG_ENDIAN_MAX_DEBUG_BUF; + datalen = BIG_ENDIAN_MAX_DEBUG_BUF-1; } - char dbgbuf[BIG_ENDIAN_MAX_DEBUG_BUF] = { 0 }; - memcpy(dbgbuf, data, datalen); + strlcpy(dbgbuf, data, datalen); SWAPME(dbgbuf, datalen); WMA_LOGD("FIRMWARE:%s", dbgbuf); return 0; } #else - WMA_LOGD("FIRMWARE:%s", data); + if (datalen == WMI_SVC_MSG_MAX_SIZE) { + WMA_LOGE("%s Invalid data len %d, limiting to max", + __func__, datalen); + datalen = WMI_SVC_MSG_MAX_SIZE -1 ; + } + + strlcpy(dbgbuf, data, datalen); + WMA_LOGD("FIRMWARE:%s", dbgbuf); return 0; #endif /* BIG_ENDIAN_HOST */ }