diff options
| author | Justin Iurman <justin.iurman@uliege.be> | 2025-02-25 18:51:38 +0100 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-03-07 16:45:42 +0100 |
| commit | c441f9281d7afb9b56eb4c0700e8d2210e33455f (patch) | |
| tree | 74521b063fb75c84b376ea820b51473ed9c81ca0 /net | |
| parent | ab9de9c48316d2622d3bf353916b99971570e2c9 (diff) | |
| download | linux-c441f9281d7afb9b56eb4c0700e8d2210e33455f.tar.gz linux-c441f9281d7afb9b56eb4c0700e8d2210e33455f.tar.bz2 linux-c441f9281d7afb9b56eb4c0700e8d2210e33455f.zip | |
net: ipv6: fix dst ref loop on input in seg6 lwt
[ Upstream commit c64a0727f9b1cbc63a5538c8c0014e9a175ad864 ]
Prevent a dst ref loop on input in seg6_iptunnel.
Fixes: af4a2209b134 ("ipv6: sr: use dst_cache in seg6_input")
Cc: David Lebrun <dlebrun@google.com>
Cc: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net')
| -rw-r--r-- | net/ipv6/seg6_iptunnel.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 4bf937bfc263..c44e4c0824e0 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -472,10 +472,18 @@ static int seg6_input_core(struct net *net, struct sock *sk, { struct dst_entry *orig_dst = skb_dst(skb); struct dst_entry *dst = NULL; + struct lwtunnel_state *lwtst; struct seg6_lwt *slwt; int err; - slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); + /* We cannot dereference "orig_dst" once ip6_route_input() or + * skb_dst_drop() is called. However, in order to detect a dst loop, we + * need the address of its lwtstate. So, save the address of lwtstate + * now and use it later as a comparison. + */ + lwtst = orig_dst->lwtstate; + + slwt = seg6_lwt_lwtunnel(lwtst); local_bh_disable(); dst = dst_cache_get(&slwt->cache); @@ -488,7 +496,9 @@ static int seg6_input_core(struct net *net, struct sock *sk, if (!dst) { ip6_route_input(skb); dst = skb_dst(skb); - if (!dst->error) { + + /* cache only if we don't create a dst reference loop */ + if (!dst->error && lwtst != dst->lwtstate) { local_bh_disable(); dst_cache_set_ip6(&slwt->cache, dst, &ipv6_hdr(skb)->saddr); |
