bnxt_en: Fix memory fault in bnxt_ethtool_init()
authorVasundhara Volam <vasundhara-v.volam@broadcom.com>
Thu, 19 Apr 2018 07:16:16 +0000 (03:16 -0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 19 Apr 2018 20:35:09 +0000 (16:35 -0400)
In some firmware images, the length of BNX_DIR_TYPE_PKG_LOG nvram type
could be greater than the fixed buffer length of 4096 bytes allocated by
the driver.  This was causing HWRM_NVM_READ to copy more data to the buffer
than the allocated size, causing general protection fault.

Fix the issue by allocating the exact buffer length returned by
HWRM_NVM_FIND_DIR_ENTRY, instead of 4096.  Move the kzalloc() call
into the bnxt_get_pkgver() function.

Fixes: 3ebf6f0a09a2 ("bnxt_en: Add installed-package firmware version reporting via Ethtool GDRVINFO")
Signed-off-by: Vasundhara Volam <vasundhara-v.volam@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_nvm_defs.h

index 1f622ca2a64f4d2e82557df6efdf87e9c4778df4..8ba14ae00e8ffcbc0849ad2080c4efca6893ff53 100644 (file)
@@ -1927,22 +1927,39 @@ static char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen)
        return retval;
 }
 
-static char *bnxt_get_pkgver(struct net_device *dev, char *buf, size_t buflen)
+static void bnxt_get_pkgver(struct net_device *dev)
 {
+       struct bnxt *bp = netdev_priv(dev);
        u16 index = 0;
-       u32 datalen;
+       char *pkgver;
+       u32 pkglen;
+       u8 *pkgbuf;
+       int len;
 
        if (bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG,
                                 BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE,
-                                &index, NULL, &datalen) != 0)
-               return NULL;
+                                &index, NULL, &pkglen) != 0)
+               return;
 
-       memset(buf, 0, buflen);
-       if (bnxt_get_nvram_item(dev, index, 0, datalen, buf) != 0)
-               return NULL;
+       pkgbuf = kzalloc(pkglen, GFP_KERNEL);
+       if (!pkgbuf) {
+               dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n",
+                       pkglen);
+               return;
+       }
+
+       if (bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf))
+               goto err;
 
-       return bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, buf,
-               datalen);
+       pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf,
+                                  pkglen);
+       if (pkgver && *pkgver != 0 && isdigit(*pkgver)) {
+               len = strlen(bp->fw_ver_str);
+               snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1,
+                        "/pkg %s", pkgver);
+       }
+err:
+       kfree(pkgbuf);
 }
 
 static int bnxt_get_eeprom(struct net_device *dev,
@@ -2615,22 +2632,10 @@ void bnxt_ethtool_init(struct bnxt *bp)
        struct hwrm_selftest_qlist_input req = {0};
        struct bnxt_test_info *test_info;
        struct net_device *dev = bp->dev;
-       char *pkglog;
        int i, rc;
 
-       pkglog = kzalloc(BNX_PKG_LOG_MAX_LENGTH, GFP_KERNEL);
-       if (pkglog) {
-               char *pkgver;
-               int len;
+       bnxt_get_pkgver(dev);
 
-               pkgver = bnxt_get_pkgver(dev, pkglog, BNX_PKG_LOG_MAX_LENGTH);
-               if (pkgver && *pkgver != 0 && isdigit(*pkgver)) {
-                       len = strlen(bp->fw_ver_str);
-                       snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1,
-                                "/pkg %s", pkgver);
-               }
-               kfree(pkglog);
-       }
        if (bp->hwrm_spec_code < 0x10704 || !BNXT_SINGLE_PF(bp))
                return;
 
index 73f2249555b57c2b0ef4470e076f4bdd442dd463..83444811d3c6bbe28b518fe91ce540d88daf55af 100644 (file)
@@ -59,8 +59,6 @@ enum bnxt_nvm_directory_type {
 #define BNX_DIR_ATTR_NO_CHKSUM                 (1 << 0)
 #define BNX_DIR_ATTR_PROP_STREAM               (1 << 1)
 
-#define BNX_PKG_LOG_MAX_LENGTH                 4096
-
 enum bnxnvm_pkglog_field_index {
        BNX_PKG_LOG_FIELD_IDX_INSTALLED_TIMESTAMP       = 0,
        BNX_PKG_LOG_FIELD_IDX_PKG_DESCRIPTION           = 1,