net.ipv4.vs.sync_refresh_period is documented as an unsigned number of seconds. proc_dointvec_jiffies() accepts a signed integer and converts it to jiffies before storing it in an unsigned int field. Consequently, writing -1 stores UINT_MAX - HZ + 1 jiffies and bypasses the finite bound applied to ordinary positive writes. This changes the behavior of ip_vs_sync_conn_needed(). With sync_threshold="0 1" (threshold 0, period 1) and sync_refresh_period=-1, only the first of twelve packets requests a sync message; the zero-refresh control requests all twelve. Store the value in seconds, as documented, and convert it at the single consumer. Use proc_douintvec_minmax() to reject negative input. Cap the value at INT_MAX / HZ to preserve the prior jiffies range and avoid overflow in secs_to_jiffies(). The issue was reproduced on an affected 7.0 distribution kernel in a temporary network namespace. A patched target kernel was built with W=1 and exercised in QEMU; -1 is now rejected with EINVAL, zero and positive values retain their behavior, and the HZ=1000 boundary accepts 2147483 while rejecting 2147484. Fixes: 749c42b620a9 ("ipvs: reduce sync rate with time thresholds") Cc: stable@vger.kernel.org Signed-off-by: Yingjie Wang <1075151112@qq.com> --- include/net/ip_vs.h | 7 ++++--- net/netfilter/ipvs/ip_vs_ctl.c | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 9a83bff32569..66f26c3d1f75 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -1267,7 +1268,7 @@ struct netns_ipvs { int sysctl_sloppy_sctp; int sysctl_expire_quiescent_template; int sysctl_sync_threshold[2]; - unsigned int sysctl_sync_refresh_period; + unsigned int sysctl_sync_refresh_period; /* seconds */ int sysctl_sync_retries; int sysctl_nat_icmp_send; int sysctl_pmtu_disc; @@ -1335,7 +1336,7 @@ struct netns_ipvs { #define DEFAULT_SYNC_VER 1 #define DEFAULT_SLOPPY_TCP 0 #define DEFAULT_SLOPPY_SCTP 0 -#define DEFAULT_SYNC_REFRESH_PERIOD (0U * HZ) +#define DEFAULT_SYNC_REFRESH_PERIOD 0U #define DEFAULT_SYNC_RETRIES 0 #define IPVS_SYNC_WAKEUP_RATE 8 #define IPVS_SYNC_QLEN_MAX (IPVS_SYNC_WAKEUP_RATE * 4) @@ -1363,7 +1364,7 @@ static inline int sysctl_sync_period(struct netns_ipvs *ipvs) static inline unsigned int sysctl_sync_refresh_period(struct netns_ipvs *ipvs) { - return READ_ONCE(ipvs->sysctl_sync_refresh_period); + return secs_to_jiffies(READ_ONCE(ipvs->sysctl_sync_refresh_period)); } static inline int sysctl_sync_retries(struct netns_ipvs *ipvs) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index ce9fe20d6106..82726b6b5e3a 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2369,6 +2369,8 @@ static int ip_vs_zero_all(struct netns_ipvs *ipvs) #ifdef CONFIG_SYSCTL +static unsigned int sync_refresh_period_max = INT_MAX / HZ; + static int proc_do_conn_max(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) @@ -2824,9 +2826,11 @@ static struct ctl_table vs_vars[] = { }, { .procname = "sync_refresh_period", - .maxlen = sizeof(int), + .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = proc_dointvec_jiffies, + .proc_handler = proc_douintvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = &sync_refresh_period_max, }, { .procname = "sync_retries", base-commit: cb284914e749388eef402938bdb3115fe1f6d337 -- 2.43.0