Re: [PATCH nf 1/1] ipvs: guard estimator enqueue until limits are set
Julian Anastasov <[email protected]> Mon, 27 Jul 2026 21:48:19 +0300 (EEST)
| Newsgroups | org.kernel.vger.lvs-devel,org.kernel.vger.netfilter-devel |
|---|---|
| Message-ID | <[email protected]> |
Hello, On Tue, 28 Jul 2026, Ren Wei wrote: > From: Zhiling Zou <[email protected]> > > IPVS estimator kthread 0 starts with zeroed chain and tick limits until > its initial calculation phase completes. If network namespace teardown > clears ipvs->enable during that phase, ip_vs_est_calc_phase() can return > without installing positive limits. > > The kthread can then drain est_temp_list with zero chain_max, tick_max > and est_max_count values. Each enqueue consumes one available tick row, > but est_count never reaches the zero est_max_count value. After all rows > are consumed, the row lookup returns IPVS_EST_NTICKS and > ip_vs_enqueue_estimator() writes past the ticks and tick_len arrays. > > Do not drain temporary estimators before est_chain_max is ready, and > reject enqueue attempts that do not have valid per-kthread limits or a > valid tick row. > > Fixes: 705dd3444081 ("ipvs: use kthreads for stats estimation") > Cc: [email protected] > Reported-by: Vega <[email protected]> > Assisted-by: Codex:gpt-5.4 > Signed-off-by: Zhiling Zou <[email protected]> > Signed-off-by: Ren Wei <[email protected]> > --- > net/netfilter/ipvs/ip_vs_est.c | 12 +++++++++++- > 1 file changed, 11 insertions(+), 1 deletion(-) > > diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c > index ab09f51829512..8c8bb2085d1e3 100644 > --- a/net/netfilter/ipvs/ip_vs_est.c > +++ b/net/netfilter/ipvs/ip_vs_est.c > @@ -196,7 +196,8 @@ static int ip_vs_estimation_kthread(void *data) > } > > while (1) { > - if (!id && !hlist_empty(&ipvs->est_temp_list)) > + if (!id && READ_ONCE(ipvs->est_chain_max) && > + !hlist_empty(&ipvs->est_temp_list)) Checking it in loop should not be needed. It is determined only once before the loop. Perhaps, we can detect the problem early: diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c index ab09f5182951..86d20f19fe31 100644 --- a/net/netfilter/ipvs/ip_vs_est.c +++ b/net/netfilter/ipvs/ip_vs_est.c @@ -191,8 +191,11 @@ static int ip_vs_estimation_kthread(void *data) } /* kthread 0 will handle the calc phase */ - if (ipvs->est_calc_phase) + if (ipvs->est_calc_phase) { ip_vs_est_calc_phase(ipvs); + if (kthread_should_stop() || !READ_ONCE(ipvs->enable)) + return 0; + } } while (1) { Or even to check ipvs->est_chain_max too but it should not be needed. > ip_vs_est_drain_temp_list(ipvs); > set_current_state(TASK_IDLE); > if (kthread_should_stop()) > @@ -421,6 +422,11 @@ static int ip_vs_enqueue_estimator(struct netns_ipvs *ipvs, > > add_est: > ktid = kd->id; > + if (!kd->chain_max || !kd->tick_max || !kd->est_max_count) { > + ret = -EINVAL; > + goto out; > + } > + > /* For small number of estimators prefer to use few ticks, > * otherwise try to add into the last estimated row. > * est_row and add_row point after the row we should use > @@ -450,6 +456,10 @@ static int ip_vs_enqueue_estimator(struct netns_ipvs *ipvs, > if (row >= IPVS_EST_NTICKS) > row = find_first_bit(kd->avail, IPVS_EST_NTICKS); > } > + if (row >= IPVS_EST_NTICKS) { > + ret = -EINVAL; > + goto out; > + } > > td = rcu_dereference_protected(kd->ticks[row], 1); > if (!td) { > -- > 2.43.0 > Regards -- Julian Anastasov <[email protected]>