From: Janardhanan Arumugam <[email protected]>

The following bounds checks are missing or can overflow:
- segment offset and size checks in DDP package verification
  can wrap around
- buffer range check of a signed DDP segment can wrap around
- package count reported by firmware is not limited to the size
  of the response buffer
- NVM access functions zero more than the size of the output buffer

Fixes: 51d04e4933e3 ("net/ice/base: add flexible pipeline module")
Fixes: f035feb47458 ("net/ice/base: support NVM access commands")
Fixes: c4afa96e4de1 ("net/ice/base: check DDP package compatibility")
Fixes: ed3066a3b1b0 ("net/ice/base: refactor DDP code")
Cc: [email protected]

Signed-off-by: Janardhanan Arumugam <[email protected]>
Signed-off-by: Vladimir Medvedkin <[email protected]>
---
 drivers/net/intel/ice/base/ice_ddp.c | 19 ++++++++++++-------
 drivers/net/intel/ice/base/ice_nvm.c |  4 ++--
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/drivers/net/intel/ice/base/ice_ddp.c 
b/drivers/net/intel/ice/base/ice_ddp.c
index ae80d93656..072d1beb83 100644
--- a/drivers/net/intel/ice/base/ice_ddp.c
+++ b/drivers/net/intel/ice/base/ice_ddp.c
@@ -519,7 +519,7 @@ ice_download_pkg_config_seg(struct ice_hw *hw, struct 
ice_pkg_hdr *pkg_hdr,
        bufs = ice_find_buf_table(seg);
        buf_count = LE32_TO_CPU(bufs->buf_count);
 
-       if (start >= buf_count || start + count > buf_count)
+       if (start >= buf_count || count > buf_count - start)
                return ICE_DDP_PKG_ERR;
 
        state = ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count,
@@ -843,6 +843,7 @@ enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw)
        struct ice_aqc_get_pkg_info_resp *pkg_info;
        u16 size;
        u32 i;
+       u32 pkg_count;
 
        size = ice_struct_size(pkg_info, pkg_info, ICE_PKG_CNT);
        pkg_info = (struct ice_aqc_get_pkg_info_resp *)ice_malloc(hw, size);
@@ -854,7 +855,8 @@ enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw)
                goto init_pkg_free_alloc;
        }
 
-       for (i = 0; i < LE32_TO_CPU(pkg_info->count); i++) {
+       pkg_count = min(LE32_TO_CPU(pkg_info->count), (u32)ICE_PKG_CNT);
+       for (i = 0; i < pkg_count; i++) {
 #define ICE_PKG_FLAG_COUNT     4
                char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 };
                u8 place = 0;
@@ -966,6 +968,7 @@ ice_enum_labels(struct ice_seg *ice_seg, u32 type, struct 
ice_pkg_enum *state,
 enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
 {
        u32 seg_count;
+       u32 off;
        u32 i;
 
        if (len < ice_struct_size(pkg, seg_offset, 1))
@@ -988,17 +991,18 @@ enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr 
*pkg, u32 len)
 
        /* all segments must fit within length */
        for (i = 0; i < seg_count; i++) {
-               u32 off = LE32_TO_CPU(pkg->seg_offset[i]);
                struct ice_generic_seg_hdr *seg;
 
+               off = LE32_TO_CPU(pkg->seg_offset[i]);
+
                /* segment header must fit */
-               if (len < off + sizeof(*seg))
+               if (len < off || len - off < sizeof(*seg))
                        return ICE_DDP_PKG_INVALID_FILE;
 
                seg = (struct ice_generic_seg_hdr *)((u8 *)pkg + off);
 
                /* segment body must fit */
-               if (len < off + LE32_TO_CPU(seg->seg_size))
+               if (len < off || len - off < LE32_TO_CPU(seg->seg_size))
                        return ICE_DDP_PKG_INVALID_FILE;
        }
 
@@ -1059,7 +1063,7 @@ ice_chk_pkg_compat(struct ice_hw *hw, struct ice_pkg_hdr 
*ospkg,
        struct ice_aqc_get_pkg_info_resp *pkg;
        enum ice_ddp_state state;
        u16 size;
-       u32 i;
+       u32 i, pkg_count;
 
        /* Check package version compatibility */
        state = ice_chk_pkg_version(&hw->pkg_ver);
@@ -1087,7 +1091,8 @@ ice_chk_pkg_compat(struct ice_hw *hw, struct ice_pkg_hdr 
*ospkg,
                goto fw_ddp_compat_free_alloc;
        }
 
-       for (i = 0; i < LE32_TO_CPU(pkg->count); i++) {
+       pkg_count = min(LE32_TO_CPU(pkg->count), (u32)ICE_PKG_CNT);
+       for (i = 0; i < pkg_count; i++) {
                /* loop till we find the NVM package */
                if (!pkg->pkg_info[i].is_in_nvm)
                        continue;
diff --git a/drivers/net/intel/ice/base/ice_nvm.c 
b/drivers/net/intel/ice/base/ice_nvm.c
index 56c6c96a95..19aa150541 100644
--- a/drivers/net/intel/ice/base/ice_nvm.c
+++ b/drivers/net/intel/ice/base/ice_nvm.c
@@ -1227,7 +1227,7 @@ ice_nvm_access_get_features(struct ice_nvm_access_cmd 
*cmd,
                return ICE_ERR_NO_MEMORY;
 
        /* Initialize the data buffer to zeros */
-       ice_memset(data, 0, cmd->data_size, ICE_NONDMA_MEM);
+       ice_memset(data, 0, sizeof(union ice_nvm_access_data), ICE_NONDMA_MEM);
 
        /* Fill in the features data */
        data->drv_features.major = ICE_NVM_ACCESS_MAJOR_VER;
@@ -1342,7 +1342,7 @@ ice_nvm_access_read(struct ice_hw *hw, struct 
ice_nvm_access_cmd *cmd,
        ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
 
        /* Always initialize the output data, even on failure */
-       ice_memset(data, 0, cmd->data_size, ICE_NONDMA_MEM);
+       ice_memset(data, 0, sizeof(union ice_nvm_access_data), ICE_NONDMA_MEM);
 
        /* Make sure this is a valid read/write access request */
        status = ice_validate_nvm_rw_reg(cmd);
-- 
2.43.0

Reply via email to