[v2,083/148] net/ice/base: fix potential TLV length overflow

Message ID 8d759a88a58f9f7aa36cf0ec74fbe16f65e529b0.1718204529.git.anatoly.burakov@intel.com (mailing list archive)
State Superseded
Delegated to: Bruce Richardson
Headers
Series Update net/ice base driver to latest upstream snapshot |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Anatoly Burakov June 12, 2024, 3:01 p.m. UTC
  From: Ian Stokes <ian.stokes@intel.com>

It's possible that an NVM with an invalid tlv_len could cause an integer
overflow of next_tlv which can result an infinite loop.

Fix this issue by changing next_tlv from u16 to u32 to prevent overflow.
Also check that tlv_len is valid and less than pfa_len.

Fix an issue with conversion from 'u32' to 'u16', possible loss
of data compile errors by making appropriate casts.

Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
Signed-off-by: Dan Nowlin <dan.nowlin@intel.com>
Signed-off-by: Ian Stokes <ian.stokes@intel.com>
---
 drivers/net/ice/base/ice_nvm.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
  

Patch

diff --git a/drivers/net/ice/base/ice_nvm.c b/drivers/net/ice/base/ice_nvm.c
index 79b66fa70f..811bbc9bbc 100644
--- a/drivers/net/ice/base/ice_nvm.c
+++ b/drivers/net/ice/base/ice_nvm.c
@@ -472,7 +472,7 @@  ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
 		       u16 module_type)
 {
 	u16 pfa_len, pfa_ptr;
-	u16 next_tlv;
+	u32 next_tlv;
 	int status;
 
 	status = ice_read_sr_word(hw, ICE_SR_PFA_PTR, &pfa_ptr);
@@ -489,25 +489,30 @@  ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
 	 * of TLVs to find the requested one.
 	 */
 	next_tlv = pfa_ptr + 1;
-	while (next_tlv < pfa_ptr + pfa_len) {
+	while (next_tlv < ((u32)pfa_ptr + pfa_len)) {
 		u16 tlv_sub_module_type;
 		u16 tlv_len;
 
 		/* Read TLV type */
-		status = ice_read_sr_word(hw, next_tlv, &tlv_sub_module_type);
+		status = ice_read_sr_word(hw, (u16)next_tlv,
+					  &tlv_sub_module_type);
 		if (status) {
 			ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV type.\n");
 			break;
 		}
 		/* Read TLV length */
-		status = ice_read_sr_word(hw, next_tlv + 1, &tlv_len);
+		status = ice_read_sr_word(hw, (u16)(next_tlv + 1), &tlv_len);
 		if (status) {
 			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 = next_tlv;
+				*module_tlv = (u16)next_tlv;
 				*module_tlv_len = tlv_len;
 				return 0;
 			}