Skip to content

Commit

Permalink
net/ice/base: fix iteration of TLVs in Preserved Fields Area
Browse files Browse the repository at this point in the history
[ upstream commit dcb760bf0f951b404bce33a1dd14906154b58c75 ]

The ice_get_pfa_module_tlv() function iterates over the Preserved Fields
Area to read data from the Shadow RAM, including the Part Board Assembly
data, among others.

If the specific TLV being requested is not found in the current NVM, the
code will read past the end of the PFA, misinterpreting the last word of
the PFA and the word just after the PFA as another TLV. This typically
results in one extra iteration before the length check of the while loop
is triggered.

Correct the logic for determining the maximum PFA offset to include the
extra last word. Additionally, make the driver robust against overflows
by using check_add_overflow. This ensures that even if the NVM provides
bogus data, the driver will not overflow, and will instead log a useful
warning message. The check for whether the TLV length exceeds the PFA
length is also removed, in favor of relying on the overflow warning
instead.

Fixes: 5d0b7b5 ("net/ice/base: add read PBA module function")

Signed-off-by: Fabio Pricoco <[email protected]>
Signed-off-by: Jacob Keller <[email protected]>
Signed-off-by: Soumyadeep Hore <[email protected]>
Acked-by: Bruce Richardson <[email protected]>
  • Loading branch information
fpricoco authored and kevintraynor committed Dec 3, 2024
1 parent 6b1b8ad commit 3ee516c
Showing 1 changed file with 24 additions and 11 deletions.
35 changes: 24 additions & 11 deletions drivers/net/ice/base/ice_nvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,7 @@ ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
u16 module_type)
{
enum ice_status status;
u16 pfa_len, pfa_ptr;
u32 next_tlv;
u16 pfa_len, pfa_ptr, next_tlv, max_tlv;

status = ice_read_sr_word(hw, ICE_SR_PFA_PTR, &pfa_ptr);
if (status != ICE_SUCCESS) {
Expand All @@ -455,12 +454,26 @@ ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
ice_debug(hw, ICE_DBG_INIT, "Failed to read PFA length.\n");
return status;
}
/* Starting with first TLV after PFA length, iterate through the list

max_tlv = pfa_ptr + pfa_len - 1;
if (pfa_ptr > max_tlv) {
ice_debug(hw, ICE_DBG_INIT, "PFA starts at offset %u. PFA length of %u caused 16-bit arithmetic overflow.\n",
pfa_ptr, pfa_len);
return ICE_ERR_INVAL_SIZE;
}

/* The Preserved Fields Area contains a sequence of TLVs which define
* its contents. The PFA length includes all of the TLVs, plus its
* initial length word itself, *and* one final word at the end of all
* of the TLVs.
*
* Starting with first TLV after PFA length, iterate through the list
* of TLVs to find the requested one.
*/
next_tlv = pfa_ptr + 1;
while (next_tlv < ((u32)pfa_ptr + pfa_len)) {
while (next_tlv < max_tlv) {
u16 tlv_sub_module_type;
u16 curr_tlv;
u16 tlv_len;

/* Read TLV type */
Expand All @@ -476,10 +489,6 @@ ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV length.\n");
break;
}
if (tlv_len > pfa_len) {
ice_debug(hw, ICE_DBG_INIT, "Invalid TLV length.\n");
return ICE_ERR_INVAL_SIZE;
}
if (tlv_sub_module_type == module_type) {
if (tlv_len) {
*module_tlv = (u16)next_tlv;
Expand All @@ -488,10 +497,14 @@ ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
}
return ICE_ERR_INVAL_SIZE;
}
/* Check next TLV, i.e. current TLV pointer + length + 2 words
* (for current TLV's type and length)
*/

curr_tlv = next_tlv;
next_tlv = next_tlv + tlv_len + 2;
if (curr_tlv > next_tlv) {
ice_debug(hw, ICE_DBG_INIT, "TLV of type %u and length 0x%04x caused 16-bit arithmetic overflow. The PFA starts at 0x%04x and has length of 0x%04x\n",
tlv_sub_module_type, tlv_len, pfa_ptr, pfa_len);
return ICE_ERR_INVAL_SIZE;
}
}
/* Module does not exist */
return ICE_ERR_DOES_NOT_EXIST;
Expand Down

0 comments on commit 3ee516c

Please sign in to comment.