]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipvs: do not leak dest after get from dest trash
authorJulian Anastasov <ja@ssi.bg>
Thu, 30 Apr 2026 07:44:16 +0000 (10:44 +0300)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 4 May 2026 23:52:55 +0000 (01:52 +0200)
Sashiko warns about leaked dest if ip_vs_start_estimator()
fails in ip_vs_add_dest(). Add ip_vs_trash_put_dest() to
put back the dest into dest trash.

Link: https://sashiko.dev/#/patchset/20260428175725.72050-1-ja%40ssi.bg
Fixes: 705dd3444081 ("ipvs: use kthreads for stats estimation")
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/ipvs/ip_vs_ctl.c

index caec516856e9534aa3edc27922a36fec36f2ba63..d81077c2457a8be7b34f49750140a83fce4dbf44 100644 (file)
@@ -1102,6 +1102,24 @@ out:
        return dest;
 }
 
+/* Put destination in trash */
+static void ip_vs_trash_put_dest(struct netns_ipvs *ipvs,
+                                struct ip_vs_dest *dest, unsigned long istart,
+                                bool cleanup)
+{
+       spin_lock_bh(&ipvs->dest_trash_lock);
+       IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
+                     IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
+                     refcount_read(&dest->refcnt));
+       if (list_empty(&ipvs->dest_trash) && !cleanup)
+               mod_timer(&ipvs->dest_trash_timer,
+                         jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
+       /* dest lives in trash with reference */
+       list_add(&dest->t_list, &ipvs->dest_trash);
+       dest->idle_start = istart;
+       spin_unlock_bh(&ipvs->dest_trash_lock);
+}
+
 static void ip_vs_dest_rcu_free(struct rcu_head *head)
 {
        struct ip_vs_dest *dest;
@@ -1461,9 +1479,12 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
                              ntohs(dest->vport));
 
                ret = ip_vs_start_estimator(svc->ipvs, &dest->stats);
+               /* On error put back dest into the trash */
                if (ret < 0)
-                       return ret;
-               __ip_vs_update_dest(svc, dest, udest, 1);
+                       ip_vs_trash_put_dest(svc->ipvs, dest, dest->idle_start,
+                                            false);
+               else
+                       __ip_vs_update_dest(svc, dest, udest, 1);
        } else {
                /*
                 * Allocate and initialize the dest structure
@@ -1533,17 +1554,7 @@ static void __ip_vs_del_dest(struct netns_ipvs *ipvs, struct ip_vs_dest *dest,
         */
        ip_vs_rs_unhash(dest);
 
-       spin_lock_bh(&ipvs->dest_trash_lock);
-       IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
-                     IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
-                     refcount_read(&dest->refcnt));
-       if (list_empty(&ipvs->dest_trash) && !cleanup)
-               mod_timer(&ipvs->dest_trash_timer,
-                         jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
-       /* dest lives in trash with reference */
-       list_add(&dest->t_list, &ipvs->dest_trash);
-       dest->idle_start = 0;
-       spin_unlock_bh(&ipvs->dest_trash_lock);
+       ip_vs_trash_put_dest(ipvs, dest, 0, cleanup);
 
        /* Queue up delayed work to expire all no destination connections.
         * No-op when CONFIG_SYSCTL is disabled.