Add bounds checking code so that any potential out-of-bound
array access is avoided

Signed-off-by: Sergey Temerkhanov <[email protected]>
Reviewed-by: Aleksandr Loktionov <[email protected]>
---
 drivers/net/ethernet/intel/ice/ice_dpll.c | 46 +++++++++++++----------
 1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c 
b/drivers/net/ethernet/intel/ice/ice_dpll.c
index f4d6c247e96e..e80460aeac11 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -758,6 +758,8 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct 
ice_dpll_pin *pin,
                          struct netlink_ext_ack *extack)
 {
        u8 parent, port_num = ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT;
+       enum dpll_pin_state eec_state = DPLL_PIN_STATE_DISCONNECTED;
+       enum dpll_pin_state pps_state = DPLL_PIN_STATE_DISCONNECTED;
        int ret;
 
        switch (pin_type) {
@@ -769,26 +771,26 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct 
ice_dpll_pin *pin,
                        goto err;
                if (ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN & pin->flags[0]) {
                        if (pin->pin) {
-                               pin->state[pf->dplls.eec.dpll_idx] =
+                               eec_state =
                                        pin->pin == pf->dplls.eec.active_input ?
                                        DPLL_PIN_STATE_CONNECTED :
                                        DPLL_PIN_STATE_SELECTABLE;
-                               pin->state[pf->dplls.pps.dpll_idx] =
+                               pps_state =
                                        pin->pin == pf->dplls.pps.active_input ?
                                        DPLL_PIN_STATE_CONNECTED :
                                        DPLL_PIN_STATE_SELECTABLE;
                        } else {
-                               pin->state[pf->dplls.eec.dpll_idx] =
-                                       DPLL_PIN_STATE_SELECTABLE;
-                               pin->state[pf->dplls.pps.dpll_idx] =
-                                       DPLL_PIN_STATE_SELECTABLE;
+                               eec_state = DPLL_PIN_STATE_SELECTABLE;
+                               pps_state = DPLL_PIN_STATE_SELECTABLE;
                        }
-               } else {
-                       pin->state[pf->dplls.eec.dpll_idx] =
-                               DPLL_PIN_STATE_DISCONNECTED;
-                       pin->state[pf->dplls.pps.dpll_idx] =
-                               DPLL_PIN_STATE_DISCONNECTED;
                }
+               /* Commit only after a successful read so lockless readers never
+                * observe a transient disconnected state.
+                */
+               if (pf->dplls.eec.dpll_idx < ICE_DPLL_RCLK_NUM_MAX)
+                       pin->state[pf->dplls.eec.dpll_idx] = eec_state;
+               if (pf->dplls.pps.dpll_idx < ICE_DPLL_RCLK_NUM_MAX)
+                       pin->state[pf->dplls.pps.dpll_idx] = pps_state;
                break;
        case ICE_DPLL_PIN_TYPE_OUTPUT:
                ret = ice_aq_get_output_pin_cfg(&pf->hw, pin->idx,
@@ -799,20 +801,17 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct 
ice_dpll_pin *pin,
 
                parent &= ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL;
                if (ICE_AQC_GET_CGU_OUT_CFG_OUT_EN & pin->flags[0]) {
-                       pin->state[pf->dplls.eec.dpll_idx] =
-                               parent == pf->dplls.eec.dpll_idx ?
+                       eec_state = parent == pf->dplls.eec.dpll_idx ?
                                DPLL_PIN_STATE_CONNECTED :
                                DPLL_PIN_STATE_DISCONNECTED;
-                       pin->state[pf->dplls.pps.dpll_idx] =
-                               parent == pf->dplls.pps.dpll_idx ?
+                       pps_state = parent == pf->dplls.pps.dpll_idx ?
                                DPLL_PIN_STATE_CONNECTED :
                                DPLL_PIN_STATE_DISCONNECTED;
-               } else {
-                       pin->state[pf->dplls.eec.dpll_idx] =
-                               DPLL_PIN_STATE_DISCONNECTED;
-                       pin->state[pf->dplls.pps.dpll_idx] =
-                               DPLL_PIN_STATE_DISCONNECTED;
                }
+               if (pf->dplls.eec.dpll_idx < ICE_DPLL_RCLK_NUM_MAX)
+                       pin->state[pf->dplls.eec.dpll_idx] = eec_state;
+               if (pf->dplls.pps.dpll_idx < ICE_DPLL_RCLK_NUM_MAX)
+                       pin->state[pf->dplls.pps.dpll_idx] = pps_state;
                break;
        case ICE_DPLL_PIN_TYPE_RCLK_INPUT:
                if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
@@ -5180,6 +5179,13 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool 
cgu)
 
        de->dpll_idx = abilities.eec_dpll_idx;
        dp->dpll_idx = abilities.pps_dpll_idx;
+       if (de->dpll_idx >= ICE_DPLL_RCLK_NUM_MAX ||
+           dp->dpll_idx >= ICE_DPLL_RCLK_NUM_MAX) {
+               dev_err(ice_pf_to_dev(pf),
+                       "invalid dpll_idx in cgu abilities: eec=%u, pps=%u\n",
+                       de->dpll_idx, dp->dpll_idx);
+               return -EINVAL;
+       }
        d->num_inputs = abilities.num_inputs;
        d->num_outputs = abilities.num_outputs;
        d->input_phase_adj_max = le32_to_cpu(abilities.max_in_phase_adj) &
-- 
2.53.0

Reply via email to