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