summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJustin Iurman <justin.iurman@uliege.be>2025-02-25 18:51:38 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-03-07 18:25:33 +0100
commitbc9ca8a185101bd5222c6c17ddb4d6539cf7b4d9 (patch)
treec74b527c7f52eae73c88bfb9adb23f9fa3389740 /net
parent7bb1ba48f709a386cacbeb839276c0ba50b9d36b (diff)
downloadlinux-bc9ca8a185101bd5222c6c17ddb4d6539cf7b4d9.tar.gz
linux-bc9ca8a185101bd5222c6c17ddb4d6539cf7b4d9.tar.bz2
linux-bc9ca8a185101bd5222c6c17ddb4d6539cf7b4d9.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.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 33833b2064c0..51583461ae29 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);
@@ -490,7 +498,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);