ip_vs_sched_persist() calls ip_vs_ct_in_get() to look up an existing connection template, which returns ct with a reference held. If the template exists but fails the ip_vs_check_template() validation, the function can leak the reference in two ways:
1. If no destination is found (scheduler returns NULL), the function returns NULL at the !dest check without calling ip_vs_conn_put(ct). 2. If a destination is found and a new template is created via ip_vs_conn_new(), the old ct pointer is overwritten without its reference being released. Fix this by adding ip_vs_conn_put(ct) before the early return when no destination is found, and before overwriting ct with the new template. Cc: [email protected] Fixes: 5b57a98c1f0d ("IPVS: compact ip_vs_sched_persist()") Signed-off-by: Wentao Liang <[email protected]> --- net/netfilter/ipvs/ip_vs_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index d40b404c1bf6..bdc3f296876a 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -536,6 +536,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc, IP_VS_DBG(1, "p-schedule: no dest found.\n"); kfree(param.pe_data); *ignored = 0; + ip_vs_conn_put(ct); return NULL; } @@ -551,6 +552,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc, if (ct == NULL) { kfree(param.pe_data); *ignored = -1; + ip_vs_conn_put(ct); return NULL; } -- 2.34.1

