Skip to content

Commit 7dc45b8

Browse files
committed
Merge: ipv6: stable backport for 9.8 phase 2
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7378 JIRA: https://issues.redhat.com/browse/RHEL-115626 * 7ac6ea4 ipv6: fix omitted netlink attributes when using RTEXT_FILTER_SKIP_STATS * 7632fed seg6: Fix validation of nexthop addresses * 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 * d45cf1e ipv6: reject malicious packets in ipv6_gso_segment() * 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> --- <small>Created 2025-09-22 09:55 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: Patrick Talbert <ptalbert@redhat.com>
2 parents a2b5a54 + ed0e40a commit 7dc45b8

File tree

8 files changed

+108
-54
lines changed

8 files changed

+108
-54
lines changed

include/linux/skbuff.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2808,6 +2808,29 @@ static inline void skb_reset_transport_header(struct sk_buff *skb)
28082808
skb->transport_header = skb->data - skb->head;
28092809
}
28102810

2811+
/**
2812+
* skb_reset_transport_header_careful - conditionally reset transport header
2813+
* @skb: buffer to alter
2814+
*
2815+
* Hardened version of skb_reset_transport_header().
2816+
*
2817+
* Returns: true if the operation was a success.
2818+
*/
2819+
static inline bool __must_check
2820+
skb_reset_transport_header_careful(struct sk_buff *skb)
2821+
{
2822+
long offset = skb->data - skb->head;
2823+
2824+
if (unlikely(offset != (typeof(skb->transport_header))offset))
2825+
return false;
2826+
2827+
if (unlikely(offset == (typeof(skb->transport_header))~0U))
2828+
return false;
2829+
2830+
skb->transport_header = offset;
2831+
return true;
2832+
}
2833+
28112834
static inline void skb_set_transport_header(struct sk_buff *skb,
28122835
const int offset)
28132836
{

net/ipv4/icmp.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -798,11 +798,12 @@ void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
798798
struct sk_buff *cloned_skb = NULL;
799799
struct ip_options opts = { 0 };
800800
enum ip_conntrack_info ctinfo;
801+
enum ip_conntrack_dir dir;
801802
struct nf_conn *ct;
802803
__be32 orig_ip;
803804

804805
ct = nf_ct_get(skb_in, &ctinfo);
805-
if (!ct || !(ct->status & IPS_SRC_NAT)) {
806+
if (!ct || !(READ_ONCE(ct->status) & IPS_NAT_MASK)) {
806807
__icmp_send(skb_in, type, code, info, &opts);
807808
return;
808809
}
@@ -817,7 +818,8 @@ void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
817818
goto out;
818819

819820
orig_ip = ip_hdr(skb_in)->saddr;
820-
ip_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.ip;
821+
dir = CTINFO2DIR(ctinfo);
822+
ip_hdr(skb_in)->saddr = ct->tuplehash[dir].tuple.src.u3.ip;
821823
__icmp_send(skb_in, type, code, info, &opts);
822824
ip_hdr(skb_in)->saddr = orig_ip;
823825
out:

net/ipv6/addrconf.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5682,6 +5682,27 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
56825682
}
56835683
}
56845684

5685+
static int inet6_fill_ifla6_stats_attrs(struct sk_buff *skb,
5686+
struct inet6_dev *idev)
5687+
{
5688+
struct nlattr *nla;
5689+
5690+
nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
5691+
if (!nla)
5692+
goto nla_put_failure;
5693+
snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
5694+
5695+
nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
5696+
if (!nla)
5697+
goto nla_put_failure;
5698+
snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
5699+
5700+
return 0;
5701+
5702+
nla_put_failure:
5703+
return -EMSGSIZE;
5704+
}
5705+
56855706
static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev,
56865707
u32 ext_filter_mask)
56875708
{
@@ -5703,18 +5724,10 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev,
57035724

57045725
/* XXX - MC not implemented */
57055726

5706-
if (ext_filter_mask & RTEXT_FILTER_SKIP_STATS)
5707-
return 0;
5708-
5709-
nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
5710-
if (!nla)
5711-
goto nla_put_failure;
5712-
snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
5713-
5714-
nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
5715-
if (!nla)
5716-
goto nla_put_failure;
5717-
snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
5727+
if (!(ext_filter_mask & RTEXT_FILTER_SKIP_STATS)) {
5728+
if (inet6_fill_ifla6_stats_attrs(skb, idev) < 0)
5729+
goto nla_put_failure;
5730+
}
57185731

57195732
nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr));
57205733
if (!nla)

net/ipv6/ip6_fib.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -438,15 +438,17 @@ struct fib6_dump_arg {
438438
static int fib6_rt_dump(struct fib6_info *rt, struct fib6_dump_arg *arg)
439439
{
440440
enum fib_event_type fib_event = FIB_EVENT_ENTRY_REPLACE;
441+
unsigned int nsiblings;
441442
int err;
442443

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

446-
if (rt->fib6_nsiblings)
447+
nsiblings = READ_ONCE(rt->fib6_nsiblings);
448+
if (nsiblings)
447449
err = call_fib6_multipath_entry_notifier(arg->nb, fib_event,
448450
rt,
449-
rt->fib6_nsiblings,
451+
nsiblings,
450452
arg->extack);
451453
else
452454
err = call_fib6_entry_notifier(arg->nb, fib_event, rt,
@@ -1122,7 +1124,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
11221124

11231125
if (rt6_duplicate_nexthop(iter, rt)) {
11241126
if (rt->fib6_nsiblings)
1125-
rt->fib6_nsiblings = 0;
1127+
WRITE_ONCE(rt->fib6_nsiblings, 0);
11261128
if (!(iter->fib6_flags & RTF_EXPIRES))
11271129
return -EEXIST;
11281130
if (!(rt->fib6_flags & RTF_EXPIRES))
@@ -1148,7 +1150,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
11481150
*/
11491151
if (rt_can_ecmp &&
11501152
rt6_qualify_for_ecmp(iter))
1151-
rt->fib6_nsiblings++;
1153+
WRITE_ONCE(rt->fib6_nsiblings,
1154+
rt->fib6_nsiblings + 1);
11521155
}
11531156

11541157
if (iter->fib6_metric > rt->fib6_metric)
@@ -1198,7 +1201,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
11981201
fib6_nsiblings = 0;
11991202
list_for_each_entry_safe(sibling, temp_sibling,
12001203
&rt->fib6_siblings, fib6_siblings) {
1201-
sibling->fib6_nsiblings++;
1204+
WRITE_ONCE(sibling->fib6_nsiblings,
1205+
sibling->fib6_nsiblings + 1);
12021206
BUG_ON(sibling->fib6_nsiblings != rt->fib6_nsiblings);
12031207
fib6_nsiblings++;
12041208
}
@@ -1243,8 +1247,9 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
12431247
list_for_each_entry_safe(sibling, next_sibling,
12441248
&rt->fib6_siblings,
12451249
fib6_siblings)
1246-
sibling->fib6_nsiblings--;
1247-
rt->fib6_nsiblings = 0;
1250+
WRITE_ONCE(sibling->fib6_nsiblings,
1251+
sibling->fib6_nsiblings - 1);
1252+
WRITE_ONCE(rt->fib6_nsiblings, 0);
12481253
list_del_rcu(&rt->fib6_siblings);
12491254
rt6_multipath_rebalance(next_sibling);
12501255
return err;
@@ -1957,8 +1962,9 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
19571962
notify_del = true;
19581963
list_for_each_entry_safe(sibling, next_sibling,
19591964
&rt->fib6_siblings, fib6_siblings)
1960-
sibling->fib6_nsiblings--;
1961-
rt->fib6_nsiblings = 0;
1965+
WRITE_ONCE(sibling->fib6_nsiblings,
1966+
sibling->fib6_nsiblings - 1);
1967+
WRITE_ONCE(rt->fib6_nsiblings, 0);
19621968
list_del_rcu(&rt->fib6_siblings);
19631969
rt6_multipath_rebalance(next_sibling);
19641970
}

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_offload.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
116116

117117
ops = rcu_dereference(inet6_offloads[proto]);
118118
if (likely(ops && ops->callbacks.gso_segment)) {
119-
skb_reset_transport_header(skb);
119+
if (!skb_reset_transport_header_careful(skb))
120+
goto out;
121+
120122
segs = ops->callbacks.gso_segment(skb, features);
121123
if (!segs)
122124
skb->network_header = skb_mac_header(skb) + nhoff - skb->head;

net/ipv6/route.c

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5226,7 +5226,8 @@ static void ip6_route_mpath_notify(struct fib6_info *rt,
52265226
*/
52275227
rcu_read_lock();
52285228

5229-
if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
5229+
if ((nlflags & NLM_F_APPEND) && rt_last &&
5230+
READ_ONCE(rt_last->fib6_nsiblings)) {
52305231
rt = list_first_or_null_rcu(&rt_last->fib6_siblings,
52315232
struct fib6_info,
52325233
fib6_siblings);
@@ -5573,32 +5574,34 @@ static int rt6_nh_nlmsg_size(struct fib6_nh *nh, void *arg)
55735574

55745575
static size_t rt6_nlmsg_size(struct fib6_info *f6i)
55755576
{
5577+
struct fib6_info *sibling;
5578+
struct fib6_nh *nh;
55765579
int nexthop_len;
55775580

55785581
if (f6i->nh) {
55795582
nexthop_len = nla_total_size(4); /* RTA_NH_ID */
55805583
nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_nlmsg_size,
55815584
&nexthop_len);
5582-
} else {
5583-
struct fib6_nh *nh = f6i->fib6_nh;
5584-
struct fib6_info *sibling;
5585-
5586-
nexthop_len = 0;
5587-
if (f6i->fib6_nsiblings) {
5588-
rt6_nh_nlmsg_size(nh, &nexthop_len);
5589-
5590-
rcu_read_lock();
5585+
goto common;
5586+
}
55915587

5592-
list_for_each_entry_rcu(sibling, &f6i->fib6_siblings,
5593-
fib6_siblings) {
5594-
rt6_nh_nlmsg_size(sibling->fib6_nh, &nexthop_len);
5595-
}
5588+
rcu_read_lock();
5589+
retry:
5590+
nh = f6i->fib6_nh;
5591+
nexthop_len = 0;
5592+
if (READ_ONCE(f6i->fib6_nsiblings)) {
5593+
rt6_nh_nlmsg_size(nh, &nexthop_len);
55965594

5597-
rcu_read_unlock();
5595+
list_for_each_entry_rcu(sibling, &f6i->fib6_siblings,
5596+
fib6_siblings) {
5597+
rt6_nh_nlmsg_size(sibling->fib6_nh, &nexthop_len);
5598+
if (!READ_ONCE(f6i->fib6_nsiblings))
5599+
goto retry;
55985600
}
5599-
nexthop_len += lwtunnel_get_encap_size(nh->fib_nh_lws);
56005601
}
5601-
5602+
rcu_read_unlock();
5603+
nexthop_len += lwtunnel_get_encap_size(nh->fib_nh_lws);
5604+
common:
56025605
return NLMSG_ALIGN(sizeof(struct rtmsg))
56035606
+ nla_total_size(16) /* RTA_SRC */
56045607
+ nla_total_size(16) /* RTA_DST */
@@ -5757,7 +5760,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
57575760
if (dst->lwtstate &&
57585761
lwtunnel_fill_encap(skb, dst->lwtstate, RTA_ENCAP, RTA_ENCAP_TYPE) < 0)
57595762
goto nla_put_failure;
5760-
} else if (rt->fib6_nsiblings) {
5763+
} else if (READ_ONCE(rt->fib6_nsiblings)) {
57615764
struct fib6_info *sibling;
57625765
struct nlattr *mp;
57635766

@@ -5859,16 +5862,21 @@ static bool fib6_info_uses_dev(const struct fib6_info *f6i,
58595862
if (f6i->fib6_nh->fib_nh_dev == dev)
58605863
return true;
58615864

5862-
if (f6i->fib6_nsiblings) {
5863-
struct fib6_info *sibling, *next_sibling;
5865+
if (READ_ONCE(f6i->fib6_nsiblings)) {
5866+
const struct fib6_info *sibling;
58645867

5865-
list_for_each_entry_safe(sibling, next_sibling,
5866-
&f6i->fib6_siblings, fib6_siblings) {
5867-
if (sibling->fib6_nh->fib_nh_dev == dev)
5868+
rcu_read_lock();
5869+
list_for_each_entry_rcu(sibling, &f6i->fib6_siblings,
5870+
fib6_siblings) {
5871+
if (sibling->fib6_nh->fib_nh_dev == dev) {
5872+
rcu_read_unlock();
58685873
return true;
5874+
}
5875+
if (!READ_ONCE(f6i->fib6_nsiblings))
5876+
break;
58695877
}
5878+
rcu_read_unlock();
58705879
}
5871-
58725880
return false;
58735881
}
58745882

net/ipv6/seg6_local.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,10 +1638,8 @@ static const struct nla_policy seg6_local_policy[SEG6_LOCAL_MAX + 1] = {
16381638
[SEG6_LOCAL_SRH] = { .type = NLA_BINARY },
16391639
[SEG6_LOCAL_TABLE] = { .type = NLA_U32 },
16401640
[SEG6_LOCAL_VRFTABLE] = { .type = NLA_U32 },
1641-
[SEG6_LOCAL_NH4] = { .type = NLA_BINARY,
1642-
.len = sizeof(struct in_addr) },
1643-
[SEG6_LOCAL_NH6] = { .type = NLA_BINARY,
1644-
.len = sizeof(struct in6_addr) },
1641+
[SEG6_LOCAL_NH4] = NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)),
1642+
[SEG6_LOCAL_NH6] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
16451643
[SEG6_LOCAL_IIF] = { .type = NLA_U32 },
16461644
[SEG6_LOCAL_OIF] = { .type = NLA_U32 },
16471645
[SEG6_LOCAL_BPF] = { .type = NLA_NESTED },

0 commit comments

Comments
 (0)