Skip to content

Commit cb489e8

Browse files
author
CKI KWF Bot
committed
Merge: ipv6: stable backport for 10.2 phase 1
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1473 JIRA: https://issues.redhat.com/browse/RHEL-115578 * 34aef2b ipv6: icmp: convert to dev_net_rcu() * b768294 ipv6: Use RCU in ip6_input() * 48145a5 ndisc: ndisc_send_redirect() must use dev_get_by_index_rcu() * ed6ae1f ndisc: extend RCU protection in ndisc_send_skb() * 54e6fe9 ipv6: prevent infinite loop in rt6_nlmsg_size() * f8d8ce1 ipv6: fix possible infinite loop in fib6_info_uses_dev() * 31d7d67 ipv6: annotate data-races around rt->fib6_nsiblings * c6dd1aa icmp: fix icmp_ndo_send address translation for reply direction Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com> Signed-off-by: Hangbin Liu <haliu@redhat.com> --- <small>Created 2025-09-22 10:02 UTC by backporter - [KWF FAQ](https://red.ht/kernel_workflow_doc) - [Slack #team-kernel-workflow](https://redhat-internal.slack.com/archives/C04LRUPMJQ5) - [Source](https://gitlab.com/cki-project/kernel-workflow/-/blob/main/webhook/utils/backporter.py) - [Documentation](https://gitlab.com/cki-project/kernel-workflow/-/blob/main/docs/README.backporter.md) - [Report an issue](https://issues.redhat.com/secure/CreateIssueDetails!init.jspa?pid=12334433&issuetype=1&priority=4&summary=backporter+webhook+issue&components=kernel-workflow+/+backporter)</small> Approved-by: Antoine Tenart <atenart@redhat.com> Approved-by: Florian Westphal <fwestpha@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents 503101a + 7d8ba78 commit cb489e8

File tree

7 files changed

+96
-66
lines changed

7 files changed

+96
-66
lines changed

net/ipv4/icmp.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -801,11 +801,12 @@ void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
801801
struct sk_buff *cloned_skb = NULL;
802802
struct ip_options opts = { 0 };
803803
enum ip_conntrack_info ctinfo;
804+
enum ip_conntrack_dir dir;
804805
struct nf_conn *ct;
805806
__be32 orig_ip;
806807

807808
ct = nf_ct_get(skb_in, &ctinfo);
808-
if (!ct || !(ct->status & IPS_SRC_NAT)) {
809+
if (!ct || !(READ_ONCE(ct->status) & IPS_NAT_MASK)) {
809810
__icmp_send(skb_in, type, code, info, &opts);
810811
return;
811812
}
@@ -820,7 +821,8 @@ void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
820821
goto out;
821822

822823
orig_ip = ip_hdr(skb_in)->saddr;
823-
ip_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.ip;
824+
dir = CTINFO2DIR(ctinfo);
825+
ip_hdr(skb_in)->saddr = ct->tuplehash[dir].tuple.src.u3.ip;
824826
__icmp_send(skb_in, type, code, info, &opts);
825827
ip_hdr(skb_in)->saddr = orig_ip;
826828
out:

net/ipv6/icmp.c

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ static int icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
7676
{
7777
/* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
7878
struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
79-
struct net *net = dev_net(skb->dev);
79+
struct net *net = dev_net_rcu(skb->dev);
8080

8181
if (type == ICMPV6_PKT_TOOBIG)
8282
ip6_update_pmtu(skb, net, info, skb->dev->ifindex, 0, sock_net_uid(net, NULL));
@@ -473,7 +473,10 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
473473

474474
if (!skb->dev)
475475
return;
476-
net = dev_net(skb->dev);
476+
477+
rcu_read_lock();
478+
479+
net = dev_net_rcu(skb->dev);
477480
mark = IP6_REPLY_MARK(net, skb->mark);
478481
/*
479482
* Make sure we respect the rules
@@ -496,7 +499,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
496499
!(type == ICMPV6_PARAMPROB &&
497500
code == ICMPV6_UNK_OPTION &&
498501
(opt_unrec(skb, info))))
499-
return;
502+
goto out;
500503

501504
saddr = NULL;
502505
}
@@ -526,7 +529,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
526529
if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
527530
net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n",
528531
&hdr->saddr, &hdr->daddr);
529-
return;
532+
goto out;
530533
}
531534

532535
/*
@@ -535,7 +538,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
535538
if (is_ineligible(skb)) {
536539
net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n",
537540
&hdr->saddr, &hdr->daddr);
538-
return;
541+
goto out;
539542
}
540543

541544
/* Needed by both icmpv6_global_allow and icmpv6_xmit_lock */
@@ -582,7 +585,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
582585
np = inet6_sk(sk);
583586

584587
if (!icmpv6_xrlim_allow(sk, type, &fl6, apply_ratelimit))
585-
goto out;
588+
goto out_unlock;
586589

587590
tmp_hdr.icmp6_type = type;
588591
tmp_hdr.icmp6_code = code;
@@ -600,7 +603,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
600603

601604
dst = icmpv6_route_lookup(net, skb, sk, &fl6);
602605
if (IS_ERR(dst))
603-
goto out;
606+
goto out_unlock;
604607

605608
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
606609

@@ -616,7 +619,6 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
616619
goto out_dst_release;
617620
}
618621

619-
rcu_read_lock();
620622
idev = __in6_dev_get(skb->dev);
621623

622624
if (ip6_append_data(sk, icmpv6_getfrag, &msg,
@@ -630,13 +632,15 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
630632
icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
631633
len + sizeof(struct icmp6hdr));
632634
}
633-
rcu_read_unlock();
635+
634636
out_dst_release:
635637
dst_release(dst);
636-
out:
638+
out_unlock:
637639
icmpv6_xmit_unlock(sk);
638640
out_bh_enable:
639641
local_bh_enable();
642+
out:
643+
rcu_read_unlock();
640644
}
641645
EXPORT_SYMBOL(icmp6_send);
642646

@@ -679,8 +683,8 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
679683
skb_pull(skb2, nhs);
680684
skb_reset_network_header(skb2);
681685

682-
rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0,
683-
skb, 0);
686+
rt = rt6_lookup(dev_net_rcu(skb->dev), &ipv6_hdr(skb2)->saddr,
687+
NULL, 0, skb, 0);
684688

685689
if (rt && rt->dst.dev)
686690
skb2->dev = rt->dst.dev;
@@ -717,7 +721,7 @@ EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);
717721

718722
static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
719723
{
720-
struct net *net = dev_net(skb->dev);
724+
struct net *net = dev_net_rcu(skb->dev);
721725
struct sock *sk;
722726
struct inet6_dev *idev;
723727
struct ipv6_pinfo *np;
@@ -832,7 +836,7 @@ enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type,
832836
u8 code, __be32 info)
833837
{
834838
struct inet6_skb_parm *opt = IP6CB(skb);
835-
struct net *net = dev_net(skb->dev);
839+
struct net *net = dev_net_rcu(skb->dev);
836840
const struct inet6_protocol *ipprot;
837841
enum skb_drop_reason reason;
838842
int inner_offset;
@@ -889,7 +893,7 @@ enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type,
889893
static int icmpv6_rcv(struct sk_buff *skb)
890894
{
891895
enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
892-
struct net *net = dev_net(skb->dev);
896+
struct net *net = dev_net_rcu(skb->dev);
893897
struct net_device *dev = icmp6_dev(skb);
894898
struct inet6_dev *idev = __in6_dev_get(dev);
895899
const struct in6_addr *saddr, *daddr;
@@ -921,7 +925,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
921925
skb_set_network_header(skb, nh);
922926
}
923927

924-
__ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS);
928+
__ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INMSGS);
925929

926930
saddr = &ipv6_hdr(skb)->saddr;
927931
daddr = &ipv6_hdr(skb)->daddr;
@@ -939,7 +943,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
939943

940944
type = hdr->icmp6_type;
941945

942-
ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type);
946+
ICMP6MSGIN_INC_STATS(dev_net_rcu(dev), idev, type);
943947

944948
switch (type) {
945949
case ICMPV6_ECHO_REQUEST:
@@ -1034,9 +1038,9 @@ static int icmpv6_rcv(struct sk_buff *skb)
10341038

10351039
csum_error:
10361040
reason = SKB_DROP_REASON_ICMP_CSUM;
1037-
__ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
1041+
__ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_CSUMERRORS);
10381042
discard_it:
1039-
__ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS);
1043+
__ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INERRORS);
10401044
drop_no_count:
10411045
kfree_skb_reason(skb, reason);
10421046
return 0;

net/ipv6/ip6_fib.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -440,15 +440,17 @@ struct fib6_dump_arg {
440440
static int fib6_rt_dump(struct fib6_info *rt, struct fib6_dump_arg *arg)
441441
{
442442
enum fib_event_type fib_event = FIB_EVENT_ENTRY_REPLACE;
443+
unsigned int nsiblings;
443444
int err;
444445

445446
if (!rt || rt == arg->net->ipv6.fib6_null_entry)
446447
return 0;
447448

448-
if (rt->fib6_nsiblings)
449+
nsiblings = READ_ONCE(rt->fib6_nsiblings);
450+
if (nsiblings)
449451
err = call_fib6_multipath_entry_notifier(arg->nb, fib_event,
450452
rt,
451-
rt->fib6_nsiblings,
453+
nsiblings,
452454
arg->extack);
453455
else
454456
err = call_fib6_entry_notifier(arg->nb, fib_event, rt,
@@ -1126,7 +1128,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
11261128

11271129
if (rt6_duplicate_nexthop(iter, rt)) {
11281130
if (rt->fib6_nsiblings)
1129-
rt->fib6_nsiblings = 0;
1131+
WRITE_ONCE(rt->fib6_nsiblings, 0);
11301132
if (!(iter->fib6_flags & RTF_EXPIRES))
11311133
return -EEXIST;
11321134
if (!(rt->fib6_flags & RTF_EXPIRES)) {
@@ -1155,7 +1157,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
11551157
*/
11561158
if (rt_can_ecmp &&
11571159
rt6_qualify_for_ecmp(iter))
1158-
rt->fib6_nsiblings++;
1160+
WRITE_ONCE(rt->fib6_nsiblings,
1161+
rt->fib6_nsiblings + 1);
11591162
}
11601163

11611164
if (iter->fib6_metric > rt->fib6_metric)
@@ -1205,7 +1208,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
12051208
fib6_nsiblings = 0;
12061209
list_for_each_entry_safe(sibling, temp_sibling,
12071210
&rt->fib6_siblings, fib6_siblings) {
1208-
sibling->fib6_nsiblings++;
1211+
WRITE_ONCE(sibling->fib6_nsiblings,
1212+
sibling->fib6_nsiblings + 1);
12091213
BUG_ON(sibling->fib6_nsiblings != rt->fib6_nsiblings);
12101214
fib6_nsiblings++;
12111215
}
@@ -1250,8 +1254,9 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
12501254
list_for_each_entry_safe(sibling, next_sibling,
12511255
&rt->fib6_siblings,
12521256
fib6_siblings)
1253-
sibling->fib6_nsiblings--;
1254-
rt->fib6_nsiblings = 0;
1257+
WRITE_ONCE(sibling->fib6_nsiblings,
1258+
sibling->fib6_nsiblings - 1);
1259+
WRITE_ONCE(rt->fib6_nsiblings, 0);
12551260
list_del_rcu(&rt->fib6_siblings);
12561261
rt6_multipath_rebalance(next_sibling);
12571262
return err;
@@ -1968,8 +1973,9 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
19681973
notify_del = true;
19691974
list_for_each_entry_safe(sibling, next_sibling,
19701975
&rt->fib6_siblings, fib6_siblings)
1971-
sibling->fib6_nsiblings--;
1972-
rt->fib6_nsiblings = 0;
1976+
WRITE_ONCE(sibling->fib6_nsiblings,
1977+
sibling->fib6_nsiblings - 1);
1978+
WRITE_ONCE(rt->fib6_nsiblings, 0);
19731979
list_del_rcu(&rt->fib6_siblings);
19741980
rt6_multipath_rebalance(next_sibling);
19751981
}

net/ipv6/ip6_icmp.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info)
5454
struct inet6_skb_parm parm = { 0 };
5555
struct sk_buff *cloned_skb = NULL;
5656
enum ip_conntrack_info ctinfo;
57+
enum ip_conntrack_dir dir;
5758
struct in6_addr orig_ip;
5859
struct nf_conn *ct;
5960

6061
ct = nf_ct_get(skb_in, &ctinfo);
61-
if (!ct || !(ct->status & IPS_SRC_NAT)) {
62+
if (!ct || !(READ_ONCE(ct->status) & IPS_NAT_MASK)) {
6263
__icmpv6_send(skb_in, type, code, info, &parm);
6364
return;
6465
}
@@ -73,7 +74,8 @@ void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info)
7374
goto out;
7475

7576
orig_ip = ipv6_hdr(skb_in)->saddr;
76-
ipv6_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.in6;
77+
dir = CTINFO2DIR(ctinfo);
78+
ipv6_hdr(skb_in)->saddr = ct->tuplehash[dir].tuple.src.u3.in6;
7779
__icmpv6_send(skb_in, type, code, info, &parm);
7880
ipv6_hdr(skb_in)->saddr = orig_ip;
7981
out:

net/ipv6/ip6_input.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -477,19 +477,23 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr,
477477
static int ip6_input_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
478478
{
479479
skb_clear_delivery_time(skb);
480-
rcu_read_lock();
481480
ip6_protocol_deliver_rcu(net, skb, 0, false);
482-
rcu_read_unlock();
483481

484482
return 0;
485483
}
486484

487485

488486
int ip6_input(struct sk_buff *skb)
489487
{
490-
return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN,
491-
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
492-
ip6_input_finish);
488+
int res;
489+
490+
rcu_read_lock();
491+
res = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN,
492+
dev_net_rcu(skb->dev), NULL, skb, skb->dev, NULL,
493+
ip6_input_finish);
494+
rcu_read_unlock();
495+
496+
return res;
493497
}
494498
EXPORT_SYMBOL_GPL(ip6_input);
495499

net/ipv6/ndisc.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -471,23 +471,28 @@ static void ip6_nd_hdr(struct sk_buff *skb,
471471
void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
472472
const struct in6_addr *saddr)
473473
{
474+
struct icmp6hdr *icmp6h = icmp6_hdr(skb);
474475
struct dst_entry *dst = skb_dst(skb);
475-
struct net *net = dev_net(skb->dev);
476-
struct sock *sk = net->ipv6.ndisc_sk;
477476
struct inet6_dev *idev;
477+
struct net *net;
478+
struct sock *sk;
478479
int err;
479-
struct icmp6hdr *icmp6h = icmp6_hdr(skb);
480480
u8 type;
481481

482482
type = icmp6h->icmp6_type;
483483

484+
rcu_read_lock();
485+
486+
net = dev_net_rcu(skb->dev);
487+
sk = net->ipv6.ndisc_sk;
484488
if (!dst) {
485489
struct flowi6 fl6;
486490
int oif = skb->dev->ifindex;
487491

488492
icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif);
489493
dst = icmp6_dst_alloc(skb->dev, &fl6);
490494
if (IS_ERR(dst)) {
495+
rcu_read_unlock();
491496
kfree_skb(skb);
492497
return;
493498
}
@@ -502,7 +507,6 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
502507

503508
ip6_nd_hdr(skb, saddr, daddr, READ_ONCE(inet6_sk(sk)->hop_limit), skb->len);
504509

505-
rcu_read_lock();
506510
idev = __in6_dev_get(dst->dev);
507511
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS);
508512

@@ -1692,7 +1696,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
16921696
bool ret;
16931697

16941698
if (netif_is_l3_master(skb->dev)) {
1695-
dev = __dev_get_by_index(dev_net(skb->dev), IPCB(skb)->iif);
1699+
dev = dev_get_by_index_rcu(dev_net(skb->dev), IPCB(skb)->iif);
16961700
if (!dev)
16971701
return;
16981702
}

0 commit comments

Comments
 (0)