Skip to content

Commit c907db8

Browse files
author
Paolo Abeni
committed
Merge branch 'fixes-for-seg6-and-rpl-lwtunnels-on-input'
Justin Iurman says: ==================== fixes for seg6 and rpl lwtunnels on input As a follow up to commit 92191dd ("net: ipv6: fix dst ref loops in rpl, seg6 and ioam6 lwtunnels"), we also need a conditional dst cache on input for seg6_iptunnel and rpl_iptunnel to prevent dst ref loops (i.e., if the packet destination did not change, we may end up recording a reference to the lwtunnel in its own cache, and the lwtunnel state will never be freed). This series provides a fix to respectively prevent a dst ref loop on input in seg6_iptunnel and rpl_iptunnel. v2: - https://lore.kernel.org/netdev/20250211221624.18435-1-justin.iurman@uliege.be/ v1: - https://lore.kernel.org/netdev/20250209193840.20509-1-justin.iurman@uliege.be/ ==================== Link: https://patch.msgid.link/20250225175139.25239-1-justin.iurman@uliege.be Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2 parents 1cf9631 + 13e55fb commit c907db8

File tree

2 files changed

+24
-4
lines changed

2 files changed

+24
-4
lines changed

net/ipv6/rpl_iptunnel.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,18 @@ static int rpl_input(struct sk_buff *skb)
262262
{
263263
struct dst_entry *orig_dst = skb_dst(skb);
264264
struct dst_entry *dst = NULL;
265+
struct lwtunnel_state *lwtst;
265266
struct rpl_lwt *rlwt;
266267
int err;
267268

268-
rlwt = rpl_lwt_lwtunnel(orig_dst->lwtstate);
269+
/* We cannot dereference "orig_dst" once ip6_route_input() or
270+
* skb_dst_drop() is called. However, in order to detect a dst loop, we
271+
* need the address of its lwtstate. So, save the address of lwtstate
272+
* now and use it later as a comparison.
273+
*/
274+
lwtst = orig_dst->lwtstate;
275+
276+
rlwt = rpl_lwt_lwtunnel(lwtst);
269277

270278
local_bh_disable();
271279
dst = dst_cache_get(&rlwt->cache);
@@ -280,7 +288,9 @@ static int rpl_input(struct sk_buff *skb)
280288
if (!dst) {
281289
ip6_route_input(skb);
282290
dst = skb_dst(skb);
283-
if (!dst->error) {
291+
292+
/* cache only if we don't create a dst reference loop */
293+
if (!dst->error && lwtst != dst->lwtstate) {
284294
local_bh_disable();
285295
dst_cache_set_ip6(&rlwt->cache, dst,
286296
&ipv6_hdr(skb)->saddr);

net/ipv6/seg6_iptunnel.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,10 +472,18 @@ static int seg6_input_core(struct net *net, struct sock *sk,
472472
{
473473
struct dst_entry *orig_dst = skb_dst(skb);
474474
struct dst_entry *dst = NULL;
475+
struct lwtunnel_state *lwtst;
475476
struct seg6_lwt *slwt;
476477
int err;
477478

478-
slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
479+
/* We cannot dereference "orig_dst" once ip6_route_input() or
480+
* skb_dst_drop() is called. However, in order to detect a dst loop, we
481+
* need the address of its lwtstate. So, save the address of lwtstate
482+
* now and use it later as a comparison.
483+
*/
484+
lwtst = orig_dst->lwtstate;
485+
486+
slwt = seg6_lwt_lwtunnel(lwtst);
479487

480488
local_bh_disable();
481489
dst = dst_cache_get(&slwt->cache);
@@ -490,7 +498,9 @@ static int seg6_input_core(struct net *net, struct sock *sk,
490498
if (!dst) {
491499
ip6_route_input(skb);
492500
dst = skb_dst(skb);
493-
if (!dst->error) {
501+
502+
/* cache only if we don't create a dst reference loop */
503+
if (!dst->error && lwtst != dst->lwtstate) {
494504
local_bh_disable();
495505
dst_cache_set_ip6(&slwt->cache, dst,
496506
&ipv6_hdr(skb)->saddr);

0 commit comments

Comments
 (0)