brcmfmac: add length check in brcmf_cfg80211_escan_handler()
authorArend Van Spriel <arend.vanspriel@broadcom.com>
Tue, 12 Sep 2017 08:47:53 +0000 (10:47 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 18 Oct 2017 07:20:40 +0000 (09:20 +0200)
commit 17df6453d4be17910456e99c5a85025aa1b7a246 upstream.

Upon handling the firmware notification for scans the length was
checked properly and may result in corrupting kernel heap memory
due to buffer overruns. This fix addresses CVE-2017-0786.

Cc: Kevin Cernekee <cernekee@chromium.org>
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c

index f18491cf793cea9dc28aa1336a061f8aaa35995d..5fecae0ba52ec91ee543515a97cda7d12fff481a 100644 (file)
@@ -2903,6 +2903,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
        struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        s32 status;
        struct brcmf_escan_result_le *escan_result_le;
+       u32 escan_buflen;
        struct brcmf_bss_info_le *bss_info_le;
        struct brcmf_bss_info_le *bss = NULL;
        u32 bi_length;
@@ -2919,11 +2920,23 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
 
        if (status == BRCMF_E_STATUS_PARTIAL) {
                brcmf_dbg(SCAN, "ESCAN Partial result\n");
+               if (e->datalen < sizeof(*escan_result_le)) {
+                       brcmf_err("invalid event data length\n");
+                       goto exit;
+               }
                escan_result_le = (struct brcmf_escan_result_le *) data;
                if (!escan_result_le) {
                        brcmf_err("Invalid escan result (NULL pointer)\n");
                        goto exit;
                }
+               escan_buflen = le32_to_cpu(escan_result_le->buflen);
+               if (escan_buflen > WL_ESCAN_BUF_SIZE ||
+                   escan_buflen > e->datalen ||
+                   escan_buflen < sizeof(*escan_result_le)) {
+                       brcmf_err("Invalid escan buffer length: %d\n",
+                                 escan_buflen);
+                       goto exit;
+               }
                if (le16_to_cpu(escan_result_le->bss_count) != 1) {
                        brcmf_err("Invalid bss_count %d: ignoring\n",
                                  escan_result_le->bss_count);
@@ -2940,9 +2953,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
                }
 
                bi_length = le32_to_cpu(bss_info_le->length);
-               if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
-                                       WL_ESCAN_RESULTS_FIXED_SIZE)) {
-                       brcmf_err("Invalid bss_info length %d: ignoring\n",
+               if (bi_length != escan_buflen - WL_ESCAN_RESULTS_FIXED_SIZE) {
+                       brcmf_err("Ignoring invalid bss_info length: %d\n",
                                  bi_length);
                        goto exit;
                }