All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf] ipvs: read the seq_mask only once on sync
@ 2026-09-09 11:13 Julian Anastasov
  2026-09-09 14:34 ` Julian Anastasov
  0 siblings, 1 reply; 2+ messages in thread
From: Julian Anastasov @ 2026-09-09 11:13 UTC (permalink / raw)
  To: Simon Horman
  Cc: Pablo Neira Ayuso, Florian Westphal, lvs-devel, netfilter-devel

Sashiko reports for possible heap buffer overflow when
generating sync message for the v0 and v1 message formats.
We should read the seq_mask from cp->flags only once because
another CPU can concurrently set the mask between the two
reads. Note that IPVS does not set the seq_mask anymore
for the ip_vs_ftp.c helper starting from commit 7f1c40757951
("IPVS: make FTP work with full NAT support") (2.6.36+).

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Link: https://sashiko.dev/#/patchset/20260903004149.1037028-1-pablo%40netfilter.org
Signed-off-by: Julian Anastasov <ja@ssi.bg>
---
 net/netfilter/ipvs/ip_vs_sync.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 5383aeafb0ae..07303d74e39f 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -543,8 +543,8 @@ static void ip_vs_sync_conn_v0(struct netns_ipvs *ipvs, struct ip_vs_conn *cp,
 	struct ip_vs_sync_conn_v0 *s;
 	struct ip_vs_sync_buff *buff;
 	struct ipvs_master_sync_state *ms;
+	unsigned int seq_mask, len;
 	int id;
-	unsigned int len;
 
 	if (unlikely(cp->af != AF_INET))
 		return;
@@ -564,8 +564,8 @@ static void ip_vs_sync_conn_v0(struct netns_ipvs *ipvs, struct ip_vs_conn *cp,
 	id = select_master_thread_id(ipvs, cp);
 	ms = &ipvs->ms[id];
 	buff = ms->sync_buff;
-	len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? FULL_CONN_SIZE :
-		SIMPLE_CONN_SIZE;
+	seq_mask = READ_ONCE(cp->flags) & IP_VS_CONN_F_SEQ_MASK;
+	len = seq_mask ? FULL_CONN_SIZE : SIMPLE_CONN_SIZE;
 	if (buff) {
 		m = (struct ip_vs_sync_mesg_v0 *) buff->mesg;
 		/* Send buffer if it is for v1 */
@@ -599,7 +599,7 @@ static void ip_vs_sync_conn_v0(struct netns_ipvs *ipvs, struct ip_vs_conn *cp,
 	s->daddr = cp->daddr.ip;
 	s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);
 	s->state = htons(cp->state);
-	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
+	if (seq_mask) {
 		struct ip_vs_sync_conn_options *opt =
 			(struct ip_vs_sync_conn_options *)&s[1];
 		memcpy(opt, &cp->sync_conn_opt, sizeof(*opt));
@@ -635,6 +635,7 @@ void ip_vs_sync_conn(struct netns_ipvs *ipvs, struct ip_vs_conn *cp, int pkts)
 	int id;
 	__u8 *p;
 	unsigned int len, pe_name_len, pad;
+	unsigned int seq_mask;
 
 	/* Handle old version of the protocol */
 	if (sysctl_sync_ver(ipvs) == 0) {
@@ -674,7 +675,8 @@ void ip_vs_sync_conn(struct netns_ipvs *ipvs, struct ip_vs_conn *cp, int pkts)
 #endif
 		len = sizeof(struct ip_vs_sync_v4);
 
-	if (cp->flags & IP_VS_CONN_F_SEQ_MASK)
+	seq_mask = READ_ONCE(cp->flags) & IP_VS_CONN_F_SEQ_MASK;
+	if (seq_mask)
 		len += sizeof(struct ip_vs_sync_conn_options) + 2;
 
 	if (cp->pe_data_len)
@@ -744,7 +746,7 @@ void ip_vs_sync_conn(struct netns_ipvs *ipvs, struct ip_vs_conn *cp, int pkts)
 		s->v4.vaddr = cp->vaddr.ip;
 		s->v4.daddr = cp->daddr.ip;
 	}
-	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
+	if (seq_mask) {
 		*(p++) = IPVS_OPT_SEQ_DATA;
 		*(p++) = sizeof(struct ip_vs_sync_conn_options);
 		hton_seq(&cp->in_seq, (struct ip_vs_seq *)p);
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH nf] ipvs: read the seq_mask only once on sync
  2026-09-09 11:13 [PATCH nf] ipvs: read the seq_mask only once on sync Julian Anastasov
@ 2026-09-09 14:34 ` Julian Anastasov
  0 siblings, 0 replies; 2+ messages in thread
From: Julian Anastasov @ 2026-09-09 14:34 UTC (permalink / raw)
  To: Simon Horman
  Cc: Pablo Neira Ayuso, Florian Westphal, lvs-devel, netfilter-devel


	Hello,

On Wed, 9 Sep 2026, Julian Anastasov wrote:

> Sashiko reports for possible heap buffer overflow when
> generating sync message for the v0 and v1 message formats.
> We should read the seq_mask from cp->flags only once because
> another CPU can concurrently set the mask between the two
> reads. Note that IPVS does not set the seq_mask anymore
> for the ip_vs_ftp.c helper starting from commit 7f1c40757951
> ("IPVS: make FTP work with full NAT support") (2.6.36+).
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Link: https://sashiko.dev/#/patchset/20260903004149.1037028-1-pablo%40netfilter.org
> Signed-off-by: Julian Anastasov <ja@ssi.bg>

	Ignore this, will send different patch with more checks...

https://sashiko.dev/#/patchset/20260909111338.44357-1-ja%40ssi.bg
        
pw-bot: changes-requested

> ---
>  net/netfilter/ipvs/ip_vs_sync.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
> 
> diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
> index 5383aeafb0ae..07303d74e39f 100644
> --- a/net/netfilter/ipvs/ip_vs_sync.c
> +++ b/net/netfilter/ipvs/ip_vs_sync.c
> @@ -543,8 +543,8 @@ static void ip_vs_sync_conn_v0(struct netns_ipvs *ipvs, struct ip_vs_conn *cp,
>  	struct ip_vs_sync_conn_v0 *s;
>  	struct ip_vs_sync_buff *buff;
>  	struct ipvs_master_sync_state *ms;
> +	unsigned int seq_mask, len;
>  	int id;
> -	unsigned int len;
>  
>  	if (unlikely(cp->af != AF_INET))
>  		return;
> @@ -564,8 +564,8 @@ static void ip_vs_sync_conn_v0(struct netns_ipvs *ipvs, struct ip_vs_conn *cp,
>  	id = select_master_thread_id(ipvs, cp);
>  	ms = &ipvs->ms[id];
>  	buff = ms->sync_buff;
> -	len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? FULL_CONN_SIZE :
> -		SIMPLE_CONN_SIZE;
> +	seq_mask = READ_ONCE(cp->flags) & IP_VS_CONN_F_SEQ_MASK;
> +	len = seq_mask ? FULL_CONN_SIZE : SIMPLE_CONN_SIZE;
>  	if (buff) {
>  		m = (struct ip_vs_sync_mesg_v0 *) buff->mesg;
>  		/* Send buffer if it is for v1 */
> @@ -599,7 +599,7 @@ static void ip_vs_sync_conn_v0(struct netns_ipvs *ipvs, struct ip_vs_conn *cp,
>  	s->daddr = cp->daddr.ip;
>  	s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);
>  	s->state = htons(cp->state);
> -	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
> +	if (seq_mask) {
>  		struct ip_vs_sync_conn_options *opt =
>  			(struct ip_vs_sync_conn_options *)&s[1];
>  		memcpy(opt, &cp->sync_conn_opt, sizeof(*opt));
> @@ -635,6 +635,7 @@ void ip_vs_sync_conn(struct netns_ipvs *ipvs, struct ip_vs_conn *cp, int pkts)
>  	int id;
>  	__u8 *p;
>  	unsigned int len, pe_name_len, pad;
> +	unsigned int seq_mask;
>  
>  	/* Handle old version of the protocol */
>  	if (sysctl_sync_ver(ipvs) == 0) {
> @@ -674,7 +675,8 @@ void ip_vs_sync_conn(struct netns_ipvs *ipvs, struct ip_vs_conn *cp, int pkts)
>  #endif
>  		len = sizeof(struct ip_vs_sync_v4);
>  
> -	if (cp->flags & IP_VS_CONN_F_SEQ_MASK)
> +	seq_mask = READ_ONCE(cp->flags) & IP_VS_CONN_F_SEQ_MASK;
> +	if (seq_mask)
>  		len += sizeof(struct ip_vs_sync_conn_options) + 2;
>  
>  	if (cp->pe_data_len)
> @@ -744,7 +746,7 @@ void ip_vs_sync_conn(struct netns_ipvs *ipvs, struct ip_vs_conn *cp, int pkts)
>  		s->v4.vaddr = cp->vaddr.ip;
>  		s->v4.daddr = cp->daddr.ip;
>  	}
> -	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
> +	if (seq_mask) {
>  		*(p++) = IPVS_OPT_SEQ_DATA;
>  		*(p++) = sizeof(struct ip_vs_sync_conn_options);
>  		hton_seq(&cp->in_seq, (struct ip_vs_seq *)p);
> -- 
> 2.55.0

Regards

--
Julian Anastasov <ja@ssi.bg>


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-09 14:34 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-09 11:13 [PATCH nf] ipvs: read the seq_mask only once on sync Julian Anastasov
2026-09-09 14:34 ` Julian Anastasov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.