Commit fbe1e01e authored by Julian Anastasov's avatar Julian Anastasov Committed by Pablo Neira Ayuso
Browse files

ipvs: do not leak dest after get from dest trash

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: 705dd344 ("ipvs: use kthreads for stats estimation")
Signed-off-by: default avatarJulian Anastasov <ja@ssi.bg>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent d493d9de
Loading
Loading
Loading
Loading
+24 −13
Original line number Diff line number Diff line
@@ -1102,6 +1102,24 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, int dest_af,
	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,8 +1479,11 @@ 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_trash_put_dest(svc->ipvs, dest, dest->idle_start,
					     false);
		else
			__ip_vs_update_dest(svc, dest, udest, 1);
	} else {
		/*
@@ -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.