]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net_sched: act_nat: use RCU in tcf_nat_dump()
authorEric Dumazet <edumazet@google.com>
Wed, 9 Jul 2025 09:02:00 +0000 (09:02 +0000)
committerJakub Kicinski <kuba@kernel.org>
Fri, 11 Jul 2025 23:01:16 +0000 (16:01 -0700)
Also storing tcf_action into struct tcf_nat_params
makes sure there is no discrepancy in tcf_nat_act().

Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250709090204.797558-9-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/tc_act/tc_nat.h
net/sched/act_nat.c

index c869274ac529b2667a5d9ebcc4a35dbd34da71bb..ae35f4009445560401b78584d165fbcc635c4ae5 100644 (file)
@@ -6,6 +6,7 @@
 #include <net/act_api.h>
 
 struct tcf_nat_parms {
+       int action;
        __be32 old_addr;
        __be32 new_addr;
        __be32 mask;
index d541f553805face5a0d444659c17e0b720aeb843..26241d80ebe03e74a92e951fb5ae065493b93277 100644 (file)
@@ -91,6 +91,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        nparm->new_addr = parm->new_addr;
        nparm->mask = parm->mask;
        nparm->flags = parm->flags;
+       nparm->action = parm->action;
 
        p = to_tcf_nat(*a);
 
@@ -130,17 +131,16 @@ TC_INDIRECT_SCOPE int tcf_nat_act(struct sk_buff *skb,
        tcf_lastuse_update(&p->tcf_tm);
        tcf_action_update_bstats(&p->common, skb);
 
-       action = READ_ONCE(p->tcf_action);
-
        parms = rcu_dereference_bh(p->parms);
+       action = parms->action;
+       if (unlikely(action == TC_ACT_SHOT))
+               goto drop;
+
        old_addr = parms->old_addr;
        new_addr = parms->new_addr;
        mask = parms->mask;
        egress = parms->flags & TCA_NAT_FLAG_EGRESS;
 
-       if (unlikely(action == TC_ACT_SHOT))
-               goto drop;
-
        noff = skb_network_offset(skb);
        if (!pskb_may_pull(skb, sizeof(*iph) + noff))
                goto drop;
@@ -268,21 +268,20 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a,
                        int bind, int ref)
 {
        unsigned char *b = skb_tail_pointer(skb);
-       struct tcf_nat *p = to_tcf_nat(a);
+       const struct tcf_nat *p = to_tcf_nat(a);
+       const struct tcf_nat_parms *parms;
        struct tc_nat opt = {
                .index    = p->tcf_index,
                .refcnt   = refcount_read(&p->tcf_refcnt) - ref,
                .bindcnt  = atomic_read(&p->tcf_bindcnt) - bind,
        };
-       struct tcf_nat_parms *parms;
        struct tcf_t t;
 
-       spin_lock_bh(&p->tcf_lock);
-
-       opt.action = p->tcf_action;
+       rcu_read_lock();
 
-       parms = rcu_dereference_protected(p->parms, lockdep_is_held(&p->tcf_lock));
+       parms = rcu_dereference(p->parms);
 
+       opt.action = parms->action;
        opt.old_addr = parms->old_addr;
        opt.new_addr = parms->new_addr;
        opt.mask = parms->mask;
@@ -294,12 +293,12 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a,
        tcf_tm_dump(&t, &p->tcf_tm);
        if (nla_put_64bit(skb, TCA_NAT_TM, sizeof(t), &t, TCA_NAT_PAD))
                goto nla_put_failure;
-       spin_unlock_bh(&p->tcf_lock);
+       rcu_read_unlock();
 
        return skb->len;
 
 nla_put_failure:
-       spin_unlock_bh(&p->tcf_lock);
+       rcu_read_unlock();
        nlmsg_trim(skb, b);
        return -1;
 }