> -----Original Message-----
> From: Binbin Deng <[email protected]>
> Sent: Tuesday, October 20, 2026 4:59 AM
> To: Nguyen, Anthony L <[email protected]>; Kitszel, Przemyslaw
> <[email protected]>; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]
> Cc: [email protected]; [email protected]; linux-
> [email protected]; Binbin Deng <[email protected]>
> Subject: [PATCH v1] i40e: Lock VF cloud filter list operations
>
> A VF's cloud-filter hlist is modified by the virtchnl add and delete
> handlers and by i40e_del_all_cloud_filters(), which runs when ADq is
> disabled or when the VF loses trusted status. These paths do not share
> a lock. In particular, the PF's async VF-message handler can process
> VIRTCHNL_OP_DEL_CLOUD_FILTER while host-side ndo_set_vf_trust() removes
> every cloud filter for that VF.
>
> The race is reachable from a guest by issuing cloud-filter virtchnl
> requests while the host revokes VF trust or disables ADq. The VF-
> message handler can traverse nodes that the bulk-delete path has already
> freed, or both paths can remove the same node. The result can be a
> KASAN use-after-free, hlist corruption, incorrect filter accounting, or
> a panic.
> The virtchnl operation-pending bit does not serialize this host-side
> trust path.
>
> Serialize cloud-filter control operations with a mutex. Hold it across
> the firmware add or delete, hlist update, and free, so bulk deletion and
> individual add/delete operations cannot observe a partially removed
> list.
> The lock is file-local and slow-path only.
>
> Found during a static-analysis-assisted audit: candidate sites were
> surfaced by a Coccinelle rule, and the reader/writer paths were
> confirmed by LLM-assisted (GLM-5.3) code inspection. Due to a lack of
> hardware infrastructureThe issue was not observed at runtime.
> It is identified by code inspection only.
>
> Fixes: e284fc280473 ("i40e: Add and delete cloud filter")
> Assisted-by: GLM-5.3 coccinelle
> Signed-off-by: Binbin Deng <[email protected]>
> ---
> drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
> b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
> index a26c3d47ec15..f73a710f42f1 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
> @@ -3740,6 +3740,8 @@ static struct i40e_vsi
> *i40e_find_vsi_from_seid(struct i40e_vf *vf, u16 seid)
> *
> * This function deletes all cloud filters
> **/
> +static DEFINE_MUTEX(i40e_vf_cloud_filter_lock);
> +
> static void i40e_del_all_cloud_filters(struct i40e_vf *vf) {
> struct i40e_cloud_filter *cfilter = NULL; @@ -3748,6 +3750,7 @@
> static void i40e_del_all_cloud_filters(struct i40e_vf *vf)
> struct hlist_node *node;
> int ret;
>
> + mutex_lock(&i40e_vf_cloud_filter_lock);
> hlist_for_each_entry_safe(cfilter, node,
> &vf->cloud_filter_list, cloud_node) {
> vsi = i40e_find_vsi_from_seid(vf, cfilter->seid); @@ -
> 3773,6 +3776,7 @@ static void i40e_del_all_cloud_filters(struct i40e_vf
> *vf)
> kfree(cfilter);
> vf->num_cloud_filters--;
> }
> + mutex_unlock(&i40e_vf_cloud_filter_lock);
> }
>
> /**
> @@ -3856,6 +3860,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf
> *vf, u8 *msg)
> }
>
> /* get the vsi to which the tc belongs to */
> + mutex_lock(&i40e_vf_cloud_filter_lock);
> vsi = pf->vsi[vf->ch[vcf->action_meta].vsi_idx];
> cfilter.seid = vsi->seid;
> cfilter.flags = vcf->field_flags;
> @@ -3870,6 +3875,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf
> *vf, u8 *msg)
> "VF %d: Failed to delete cloud filter, err %pe
> aq_err %s\n",
> vf->vf_id, ERR_PTR(ret),
> libie_aq_str(pf->hw.aq.asq_last_status));
> + mutex_unlock(&i40e_vf_cloud_filter_lock);
> goto err;
> }
>
> @@ -3901,6 +3907,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf
> *vf, u8 *msg)
> kfree(cf);
> vf->num_cloud_filters--;
> }
> + mutex_unlock(&i40e_vf_cloud_filter_lock);
>
> err:
> return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_CLOUD_FILTER,
> @@ -4002,6 +4009,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf
> *vf, u8 *msg)
> }
>
> /* get the VSI to which the TC belongs to */
> + mutex_lock(&i40e_vf_cloud_filter_lock);
> vsi = pf->vsi[vf->ch[vcf->action_meta].vsi_idx];
> cfilter->seid = vsi->seid;
> cfilter->flags = vcf->field_flags;
> @@ -4016,6 +4024,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf
> *vf, u8 *msg)
> "VF %d: Failed to add cloud filter, err %pe aq_err
> %s\n",
> vf->vf_id, ERR_PTR(aq_ret),
> libie_aq_str(pf->hw.aq.asq_last_status));
> + mutex_unlock(&i40e_vf_cloud_filter_lock);
> goto err_free;
> }
>
> @@ -4024,6 +4033,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf
> *vf, u8 *msg)
> /* release the pointer passing it to the collection */
> cfilter = NULL;
> vf->num_cloud_filters++;
> + mutex_unlock(&i40e_vf_cloud_filter_lock);
> err_free:
> kfree(cfilter);
> err_out:
> --
> 2.43.0
I'm afraid one more global lock shared among all cards on server will make
things worse.
@Jakub Kicinski can you comment?