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)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 20 Sep 2017 04:46:29 +0000 (07:46 +0300)
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: stable@vger.kernel.org # v4.0.x
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>
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c

index aaed4ab503ad16c6f4de0e3ccec5b83c3f85c6a1..26a0de371c2667ce42ede40098713bda0f7c8a7b 100644 (file)
@@ -3162,6 +3162,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;
@@ -3181,11 +3182,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 > BRCMF_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);
@@ -3202,9 +3215,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;
                }