From: Sandeep Penigalapati <[email protected]>

This fixes two issues in the i40e Flow Director flexible payload path.

The bitmask array bound was checked after the write to
bitmask[nb_bitmask], allowing a one-slot out-of-bounds write when the
number of partial-mask words exceeds I40E_FDIR_BITMASK_NUM_WORD. Move
the check before the write and use '>=' so the array is never indexed
out of bounds.

In addition, i40e_flow_set_fdir_flex_pit() programs the global GLQF_ORT
register, which is shared by all PFs on the NIC. It was called before
the flex mask was validated, so a rule that is later rejected still left
the global register modified, affecting other PFs. Validate the flex
mask first and only touch the hardware registers once it has passed.

Fixes: 6ced3dd72f5f ("net/i40e: support flexible payload parsing for FDIR")
Cc: [email protected]
Signed-off-by: Sandeep Penigalapati <[email protected]>
---
 drivers/net/intel/i40e/i40e_fdir.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/net/intel/i40e/i40e_fdir.c 
b/drivers/net/intel/i40e/i40e_fdir.c
index ad256a5a11..8a233f8a97 100644
--- a/drivers/net/intel/i40e/i40e_fdir.c
+++ b/drivers/net/intel/i40e/i40e_fdir.c
@@ -1230,12 +1230,12 @@ i40e_flow_store_flex_mask(struct i40e_pf *pf,
                        flex_mask.word_mask |=
                                I40E_FLEX_WORD_MASK(i / sizeof(uint16_t));
                        if (mask_tmp != UINT16_MAX) {
+                               if (nb_bitmask >= I40E_FDIR_BITMASK_NUM_WORD)
+                                       return -1;
                                flex_mask.bitmask[nb_bitmask].mask = ~mask_tmp;
                                flex_mask.bitmask[nb_bitmask].offset =
                                        i / sizeof(uint16_t);
                                nb_bitmask++;
-                               if (nb_bitmask > I40E_FDIR_BITMASK_NUM_WORD)
-                                       return -1;
                        }
                }
        }
@@ -1488,15 +1488,17 @@ i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
                                }
                        }
 
-                       if (cfg_flex_pit)
-                               i40e_flow_set_fdir_flex_pit(pf, layer_idx,
-                                               filter->input.flow_ext.raw_id);
-
                        /* Store flex mask to SW */
                        for (i = 0; i < I40E_FDIR_MAX_FLEX_LEN; i++)
                                flex_mask[i] =
                                        filter->input.flow_ext.flex_mask[i];
 
+                       /* Validate the flex mask before writing any hardware
+                        * register. i40e_flow_set_fdir_flex_pit() below 
programs
+                        * the global GLQF_ORT register, which is shared by all
+                        * PFs on the NIC, so it must not be touched for a rule
+                        * that is going to be rejected.
+                        */
                        ret = i40e_flow_store_flex_mask(pf, pctype, flex_mask);
                        if (ret == -1) {
                                PMD_DRV_LOG(ERR, "Exceed maximal"
@@ -1506,9 +1508,14 @@ i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
                                PMD_DRV_LOG(ERR, "Conflict with the"
                                            " first flexible rule");
                                return -EINVAL;
-                       } else if (ret == 0) {
-                               i40e_flow_set_fdir_flex_msk(pf, pctype);
                        }
+
+                       if (cfg_flex_pit)
+                               i40e_flow_set_fdir_flex_pit(pf, layer_idx,
+                                               filter->input.flow_ext.raw_id);
+
+                       if (ret == 0)
+                               i40e_flow_set_fdir_flex_msk(pf, pctype);
                }
 
                ret = i40e_sw_fdir_filter_insert(pf, &check_filter);
-- 
2.27.0

Reply via email to