On Fri, Mar 07, 2025 at 03:19:01AM +0000, Hangbin Liu wrote:

...

> @@ -616,9 +615,22 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
>               return;
>  
>       mutex_lock(&bond->ipsec_lock);
> -     list_for_each_entry(ipsec, &bond->ipsec_list, list) {
> -             if (!ipsec->xs->xso.real_dev)
> +     list_for_each_entry_safe(ipsec, tmp_ipsec, &bond->ipsec_list, list) {
> +             spin_lock_bh(&ipsec->xs->lock);
> +             if (!ipsec->xs->xso.real_dev) {
> +                     spin_unlock_bh(&ipsec->xs->lock);
>                       continue;
> +             }
> +
> +             if (ipsec->xs->km.state == XFRM_STATE_DEAD) {
> +                     list_del(&ipsec->list);
> +                     kfree(ipsec);

Hi Hangbin,

Apologies if this was covered elsewhere, but ipsec is kfree'd here...


> +                     /* Need to free device here, or the xs->xso.real_dev
> +                      * may changed in bond_ipsec_add_sa_all and free
> +                      * on old device will never be called.
> +                      */
> +                     goto next;
> +             }
>  
>               if (!real_dev->xfrmdev_ops ||
>                   !real_dev->xfrmdev_ops->xdo_dev_state_delete ||
> @@ -626,11 +638,20 @@ static void bond_ipsec_del_sa_all(struct bonding *bond)
>                       slave_warn(bond_dev, real_dev,
>                                  "%s: no slave xdo_dev_state_delete\n",
>                                  __func__);
> -             } else {
> -                     real_dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs);
> -                     if (real_dev->xfrmdev_ops->xdo_dev_state_free)
> -                             
> real_dev->xfrmdev_ops->xdo_dev_state_free(ipsec->xs);
> +                     spin_unlock_bh(&ipsec->xs->lock);
> +                     continue;
>               }
> +
> +             real_dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs);
> +
> +next:
> +             /* set real_dev to NULL in case __xfrm_state_delete() is called 
> in parallel */
> +             ipsec->xs->xso.real_dev = NULL;

... and the dereferenced here.

Flagged by Smatch.

> +
> +             /* Unlock before freeing device state, it could sleep. */
> +             spin_unlock_bh(&ipsec->xs->lock);
> +             if (real_dev->xfrmdev_ops->xdo_dev_state_free)
> +                     real_dev->xfrmdev_ops->xdo_dev_state_free(ipsec->xs);
>       }
>       mutex_unlock(&bond->ipsec_lock);
>  }

...

Reply via email to