Hello, On Tue, 26 Aug 2025, Zhang Tengfei wrote: > A data-race was detected by KCSAN between ip_vs_add_service() which > acts as a writer, and ip_vs_out_hook() which acts as a reader. This > can lead to unpredictable behavior and crashes. One observed symptom > is the "no destination available" error when processing packets. > > The race occurs on the `enable` flag within the `netns_ipvs` > struct. This flag was being written in the configuration path without > any protection, while concurrently being read in the packet processing > path. This lack of synchronization means a reader on one CPU could see a > partially initialized service, leading to incorrect behavior. > > To fix this, convert the `enable` flag from a plain integer to an > atomic_t. This ensures that all reads and writes to the flag are atomic. > More importantly, using atomic_set() and atomic_read() provides the > necessary memory barriers to guarantee that changes to other fields of > the service are visible to the reader CPU before the service is marked > as enabled. > > Reported-by: syzbot+1651b5234028c294c339@xxxxxxxxxxxxxxxxxxxxxxxxx > Closes: https://syzkaller.appspot.com/bug?extid=1651b5234028c294c339 > Signed-off-by: Zhang Tengfei <zhtfdev@xxxxxxxxx> > --- > include/net/ip_vs.h | 2 +- > net/netfilter/ipvs/ip_vs_conn.c | 4 ++-- > net/netfilter/ipvs/ip_vs_core.c | 10 +++++----- > net/netfilter/ipvs/ip_vs_ctl.c | 6 +++--- > net/netfilter/ipvs/ip_vs_est.c | 16 ++++++++-------- > 5 files changed, 19 insertions(+), 19 deletions(-) > > diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c > index 15049b826732..c5aa2660de92 100644 > --- a/net/netfilter/ipvs/ip_vs_est.c > +++ b/net/netfilter/ipvs/ip_vs_est.c ... > @@ -757,7 +757,7 @@ static void ip_vs_est_calc_phase(struct netns_ipvs *ipvs) > mutex_lock(&ipvs->est_mutex); > for (id = 1; id < ipvs->est_kt_count; id++) { > /* netns clean up started, abort */ > - if (!ipvs->enable) > + if (!atomic_read(&ipvs->enable)) > goto unlock2; It is a simple flag but as it is checked in loops in a few places in ip_vs_est.c, lets use READ_ONCE/WRITE_ONCE as suggested by Florian and Eric. The 3 checks in hooks in ip_vs_core.c can be simply removed: in ip_vs_out_hook, ip_vs_in_hook and ip_vs_forward_icmp. We can see enable=0 in rare cases which is not fatal. It is a flying packet in two possible cases: 1. after hooks are registered but before the flag is set 2. after the hooks are unregistered on cleanup_net Regards -- Julian Anastasov <ja@xxxxxx>