]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net/mlx5e: Prevent concurrent access to IPSec ASO context
authorJianbo Liu <jianbol@nvidia.com>
Mon, 16 Mar 2026 09:46:02 +0000 (11:46 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 19 Mar 2026 00:54:53 +0000 (17:54 -0700)
The query or updating IPSec offload object is through Access ASO WQE.
The driver uses a single mlx5e_ipsec_aso struct for each PF, which
contains a shared DMA-mapped context for all ASO operations.

A race condition exists because the ASO spinlock is released before
the hardware has finished processing WQE. If a second operation is
initiated immediately after, it overwrites the shared context in the
DMA area.

When the first operation's completion is processed later, it reads
this corrupted context, leading to unexpected behavior and incorrect
results.

This commit fixes the race by introducing a private context within
each IPSec offload object. The shared ASO context is now copied to
this private context while the ASO spinlock is held. Subsequent
processing uses this saved, per-object context, ensuring its integrity
is maintained.

Fixes: 1ed78fc03307 ("net/mlx5e: Update IPsec soft and hard limits")
Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20260316094603.6999-3-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c

index f8eaaf37963b112aeda391f87f1fd3cfaad71579..abcbd38db9dbbe6f35782a82768f8e2b7d423154 100644 (file)
@@ -287,6 +287,7 @@ struct mlx5e_ipsec_sa_entry {
        struct mlx5e_ipsec_dwork *dwork;
        struct mlx5e_ipsec_limits limits;
        u32 rx_mapped_id;
+       u8 ctx[MLX5_ST_SZ_BYTES(ipsec_aso)];
 };
 
 struct mlx5_accel_pol_xfrm_attrs {
index 33344e00719b81e15785f827ec475527aaddd0a1..71222f7247f131cda1f463a24ce6baaaeaef8ab6 100644 (file)
@@ -370,20 +370,18 @@ static void mlx5e_ipsec_aso_update_soft(struct mlx5e_ipsec_sa_entry *sa_entry,
 static void mlx5e_ipsec_handle_limits(struct mlx5e_ipsec_sa_entry *sa_entry)
 {
        struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
-       struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
-       struct mlx5e_ipsec_aso *aso = ipsec->aso;
        bool soft_arm, hard_arm;
        u64 hard_cnt;
 
        lockdep_assert_held(&sa_entry->x->lock);
 
-       soft_arm = !MLX5_GET(ipsec_aso, aso->ctx, soft_lft_arm);
-       hard_arm = !MLX5_GET(ipsec_aso, aso->ctx, hard_lft_arm);
+       soft_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, soft_lft_arm);
+       hard_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, hard_lft_arm);
        if (!soft_arm && !hard_arm)
                /* It is not lifetime event */
                return;
 
-       hard_cnt = MLX5_GET(ipsec_aso, aso->ctx, remove_flow_pkt_cnt);
+       hard_cnt = MLX5_GET(ipsec_aso, sa_entry->ctx, remove_flow_pkt_cnt);
        if (!hard_cnt || hard_arm) {
                /* It is possible to see packet counter equal to zero without
                 * hard limit event armed. Such situation can be if packet
@@ -454,10 +452,8 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
                container_of(_work, struct mlx5e_ipsec_work, work);
        struct mlx5e_ipsec_sa_entry *sa_entry = work->data;
        struct mlx5_accel_esp_xfrm_attrs *attrs;
-       struct mlx5e_ipsec_aso *aso;
        int ret;
 
-       aso = sa_entry->ipsec->aso;
        attrs = &sa_entry->attrs;
 
        spin_lock_bh(&sa_entry->x->lock);
@@ -466,8 +462,9 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
                goto unlock;
 
        if (attrs->replay_esn.trigger &&
-           !MLX5_GET(ipsec_aso, aso->ctx, esn_event_arm)) {
-               u32 mode_param = MLX5_GET(ipsec_aso, aso->ctx, mode_parameter);
+           !MLX5_GET(ipsec_aso, sa_entry->ctx, esn_event_arm)) {
+               u32 mode_param = MLX5_GET(ipsec_aso, sa_entry->ctx,
+                                         mode_parameter);
 
                mlx5e_ipsec_update_esn_state(sa_entry, mode_param);
        }
@@ -629,6 +626,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
                        /* We are in atomic context */
                        udelay(10);
        } while (ret && time_is_after_jiffies(expires));
+       if (!ret)
+               memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso));
        spin_unlock_bh(&aso->lock);
        return ret;
 }