lkml.org 
[lkml]   [2022]   [Apr]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.17 077/219] net/sched: fix initialization order when updating chain 0 head
    Date
    From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>

    [ Upstream commit e65812fd22eba32f11abe28cb377cbd64cfb1ba0 ]

    Currently, when inserting a new filter that needs to sit at the head
    of chain 0, it will first update the heads pointer on all devices using
    the (shared) block, and only then complete the initialization of the new
    element so that it has a "next" element.

    This can lead to a situation that the chain 0 head is propagated to
    another CPU before the "next" initialization is done. When this race
    condition is triggered, packets being matched on that CPU will simply
    miss all other filters, and will flow through the stack as if there were
    no other filters installed. If the system is using OVS + TC, such
    packets will get handled by vswitchd via upcall, which results in much
    higher latency and reordering. For other applications it may result in
    packet drops.

    This is reproducible with a tc only setup, but it varies from system to
    system. It could be reproduced with a shared block amongst 10 veth
    tunnels, and an ingress filter mirroring packets to another veth.
    That's because using the last added veth tunnel to the shared block to
    do the actual traffic, it makes the race window bigger and easier to
    trigger.

    The fix is rather simple, to just initialize the next pointer of the new
    filter instance (tp) before propagating the head change.

    The fixes tag is pointing to the original code though this issue should
    only be observed when using it unlocked.

    Fixes: 2190d1d0944f ("net: sched: introduce helpers to work with filter chains")
    Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
    Signed-off-by: Vlad Buslov <vladbu@nvidia.com>
    Reviewed-by: Davide Caratti <dcaratti@redhat.com>
    Link: https://lore.kernel.org/r/b97d5f4eaffeeb9d058155bcab63347527261abf.1649341369.git.marcelo.leitner@gmail.com
    Signed-off-by: Jakub Kicinski <kuba@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/sched/cls_api.c | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)

    diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
    index 5ce1208a6ea3..130b5fda9c51 100644
    --- a/net/sched/cls_api.c
    +++ b/net/sched/cls_api.c
    @@ -1653,10 +1653,10 @@ static int tcf_chain_tp_insert(struct tcf_chain *chain,
    if (chain->flushing)
    return -EAGAIN;

    + RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain, chain_info));
    if (*chain_info->pprev == chain->filter_chain)
    tcf_chain0_head_change(chain, tp);
    tcf_proto_get(tp);
    - RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain, chain_info));
    rcu_assign_pointer(*chain_info->pprev, tp);

    return 0;
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-04-18 14:24    [W:2.043 / U:1.192 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site