]> www.infradead.org Git - users/hch/misc.git/commitdiff
net: ipv6: fix dst ref loop on input in seg6 lwt
authorJustin Iurman <justin.iurman@uliege.be>
Tue, 25 Feb 2025 17:51:38 +0000 (18:51 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 27 Feb 2025 13:18:21 +0000 (14:18 +0100)
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>
net/ipv6/seg6_iptunnel.c

index 33833b2064c072b7f1647cc41392bccbb11eb275..51583461ae29ba37869133f9380f25cb7dd6be34 100644 (file)
@@ -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);