ACK: [[SCRIPT=remove_re|Re: [PATCH 1/1] netfilter: ipset: Fix wraparound in hash:*net* types]]

Stefan Bader stefan.bader at canonical.com
Fri Feb 22 10:10:13 UTC 2019


On 21.02.19 11:42, Kai-Heng Feng wrote:
> From: Jozsef Kadlecsik <kadlec at blackhole.kfki.hu>
> 
> BugLink: https://bugs.launchpad.net/bugs/1811394
> 
> Fix wraparound bug which could lead to memory exhaustion when adding an
> x.x.x.x-255.255.255.255 range to any hash:*net* types.
> 
> Fixes Netfilter's bugzilla id #1212, reported by Thomas Schwark.
> 
> Fixes: 48596a8ddc46 ("netfilter: ipset: Fix adding an IPv4 range containing more than 2^31 addresses")
> Signed-off-by: Jozsef Kadlecsik <kadlec at blackhole.kfki.hu>
> Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>
> (cherry picked from commit 0b8d9073539e217f79ec1bff65eb205ac796723d)
> Signed-off-by: Kai-Heng Feng <kai.heng.feng at canonical.com>
Acked-by: Stefan Bader <stefan.bader at canonical.com>
> ---

Cherry-pick, tested.

>  net/netfilter/ipset/ip_set_hash_ipportnet.c  | 26 +++++++--------
>  net/netfilter/ipset/ip_set_hash_net.c        |  9 +++--
>  net/netfilter/ipset/ip_set_hash_netiface.c   |  9 +++--
>  net/netfilter/ipset/ip_set_hash_netnet.c     | 28 ++++++++--------
>  net/netfilter/ipset/ip_set_hash_netport.c    | 19 ++++++-----
>  net/netfilter/ipset/ip_set_hash_netportnet.c | 35 ++++++++++----------
>  6 files changed, 63 insertions(+), 63 deletions(-)
> 
> diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
> index 0f164e986bf1..88b83d6d3084 100644
> --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
> +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
> @@ -168,7 +168,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
>  	u32 ip = 0, ip_to = 0, p = 0, port, port_to;
> -	u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
> +	u32 ip2_from = 0, ip2_to = 0, ip2;
>  	bool with_ports = false;
>  	u8 cidr;
>  	int ret;
> @@ -269,22 +269,21 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
>  	}
>  
> -	if (retried)
> +	if (retried) {
>  		ip = ntohl(h->next.ip);
> +		p = ntohs(h->next.port);
> +		ip2 = ntohl(h->next.ip2);
> +	} else {
> +		p = port;
> +		ip2 = ip2_from;
> +	}
>  	for (; ip <= ip_to; ip++) {
>  		e.ip = htonl(ip);
> -		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
> -						       : port;
>  		for (; p <= port_to; p++) {
>  			e.port = htons(p);
> -			ip2 = retried &&
> -			      ip == ntohl(h->next.ip) &&
> -			      p == ntohs(h->next.port)
> -				? ntohl(h->next.ip2) : ip2_from;
> -			while (ip2 <= ip2_to) {
> +			do {
>  				e.ip2 = htonl(ip2);
> -				ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
> -								&cidr);
> +				ip2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr);
>  				e.cidr = cidr - 1;
>  				ret = adtfn(set, &e, &ext, &ext, flags);
>  
> @@ -292,9 +291,10 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  					return ret;
>  
>  				ret = 0;
> -				ip2 = ip2_last + 1;
> -			}
> +			} while (ip2++ < ip2_to);
> +			ip2 = ip2_from;
>  		}
> +		p = port;
>  	}
>  	return ret;
>  }
> diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
> index 1c67a1761e45..5449e23af13a 100644
> --- a/net/netfilter/ipset/ip_set_hash_net.c
> +++ b/net/netfilter/ipset/ip_set_hash_net.c
> @@ -143,7 +143,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_net4_elem e = { .cidr = HOST_MASK };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
> -	u32 ip = 0, ip_to = 0, last;
> +	u32 ip = 0, ip_to = 0;
>  	int ret;
>  
>  	if (tb[IPSET_ATTR_LINENO])
> @@ -193,16 +193,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	}
>  	if (retried)
>  		ip = ntohl(h->next.ip);
> -	while (ip <= ip_to) {
> +	do {
>  		e.ip = htonl(ip);
> -		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
> +		ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
>  		ret = adtfn(set, &e, &ext, &ext, flags);
>  		if (ret && !ip_set_eexist(ret, flags))
>  			return ret;
>  
>  		ret = 0;
> -		ip = last + 1;
> -	}
> +	} while (ip++ < ip_to);
>  	return ret;
>  }
>  
> diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
> index d417074f1c1a..f5164c1efce2 100644
> --- a/net/netfilter/ipset/ip_set_hash_netiface.c
> +++ b/net/netfilter/ipset/ip_set_hash_netiface.c
> @@ -200,7 +200,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
> -	u32 ip = 0, ip_to = 0, last;
> +	u32 ip = 0, ip_to = 0;
>  	int ret;
>  
>  	if (tb[IPSET_ATTR_LINENO])
> @@ -255,17 +255,16 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
>  
>  	if (retried)
>  		ip = ntohl(h->next.ip);
> -	while (ip <= ip_to) {
> +	do {
>  		e.ip = htonl(ip);
> -		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
> +		ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
>  		ret = adtfn(set, &e, &ext, &ext, flags);
>  
>  		if (ret && !ip_set_eexist(ret, flags))
>  			return ret;
>  
>  		ret = 0;
> -		ip = last + 1;
> -	}
> +	} while (ip++ < ip_to);
>  	return ret;
>  }
>  
> diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c
> index 7f9ae2e9645b..5a2b923bd81f 100644
> --- a/net/netfilter/ipset/ip_set_hash_netnet.c
> +++ b/net/netfilter/ipset/ip_set_hash_netnet.c
> @@ -169,8 +169,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_netnet4_elem e = { };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
> -	u32 ip = 0, ip_to = 0, last;
> -	u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2;
> +	u32 ip = 0, ip_to = 0;
> +	u32 ip2 = 0, ip2_from = 0, ip2_to = 0;
>  	int ret;
>  
>  	if (tb[IPSET_ATTR_LINENO])
> @@ -247,27 +247,27 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
>  	}
>  
> -	if (retried)
> +	if (retried) {
>  		ip = ntohl(h->next.ip[0]);
> +		ip2 = ntohl(h->next.ip[1]);
> +	} else {
> +		ip2 = ip2_from;
> +	}
>  
> -	while (ip <= ip_to) {
> +	do {
>  		e.ip[0] = htonl(ip);
> -		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
> -		ip2 = (retried &&
> -		       ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1])
> -						   : ip2_from;
> -		while (ip2 <= ip2_to) {
> +		ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
> +		do {
>  			e.ip[1] = htonl(ip2);
> -			last2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]);
> +			ip2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]);
>  			ret = adtfn(set, &e, &ext, &ext, flags);
>  			if (ret && !ip_set_eexist(ret, flags))
>  				return ret;
>  
>  			ret = 0;
> -			ip2 = last2 + 1;
> -		}
> -		ip = last + 1;
> -	}
> +		} while (ip2++ < ip2_to);
> +		ip2 = ip2_from;
> +	} while (ip++ < ip_to);
>  	return ret;
>  }
>  
> diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
> index e6ef382febe4..1a187be9ebc8 100644
> --- a/net/netfilter/ipset/ip_set_hash_netport.c
> +++ b/net/netfilter/ipset/ip_set_hash_netport.c
> @@ -161,7 +161,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
> -	u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;
> +	u32 port, port_to, p = 0, ip = 0, ip_to = 0;
>  	bool with_ports = false;
>  	u8 cidr;
>  	int ret;
> @@ -239,25 +239,26 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
>  	}
>  
> -	if (retried)
> +	if (retried) {
>  		ip = ntohl(h->next.ip);
> -	while (ip <= ip_to) {
> +		p = ntohs(h->next.port);
> +	} else {
> +		p = port;
> +	}
> +	do {
>  		e.ip = htonl(ip);
> -		last = ip_set_range_to_cidr(ip, ip_to, &cidr);
> +		ip = ip_set_range_to_cidr(ip, ip_to, &cidr);
>  		e.cidr = cidr - 1;
> -		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
> -						       : port;
>  		for (; p <= port_to; p++) {
>  			e.port = htons(p);
>  			ret = adtfn(set, &e, &ext, &ext, flags);
> -
>  			if (ret && !ip_set_eexist(ret, flags))
>  				return ret;
>  
>  			ret = 0;
>  		}
> -		ip = last + 1;
> -	}
> +		p = port;
> +	} while (ip++ < ip_to);
>  	return ret;
>  }
>  
> diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c
> index 8602f2595a1a..d391485a6acd 100644
> --- a/net/netfilter/ipset/ip_set_hash_netportnet.c
> +++ b/net/netfilter/ipset/ip_set_hash_netportnet.c
> @@ -184,8 +184,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_netportnet4_elem e = { };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
> -	u32 ip = 0, ip_to = 0, ip_last, p = 0, port, port_to;
> -	u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
> +	u32 ip = 0, ip_to = 0, p = 0, port, port_to;
> +	u32 ip2_from = 0, ip2_to = 0, ip2;
>  	bool with_ports = false;
>  	int ret;
>  
> @@ -288,33 +288,34 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
>  	}
>  
> -	if (retried)
> +	if (retried) {
>  		ip = ntohl(h->next.ip[0]);
> +		p = ntohs(h->next.port);
> +		ip2 = ntohl(h->next.ip[1]);
> +	} else {
> +		p = port;
> +		ip2 = ip2_from;
> +	}
>  
> -	while (ip <= ip_to) {
> +	do {
>  		e.ip[0] = htonl(ip);
> -		ip_last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
> -		p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
> -							  : port;
> +		ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
>  		for (; p <= port_to; p++) {
>  			e.port = htons(p);
> -			ip2 = (retried && ip == ntohl(h->next.ip[0]) &&
> -			       p == ntohs(h->next.port)) ? ntohl(h->next.ip[1])
> -							 : ip2_from;
> -			while (ip2 <= ip2_to) {
> +			do {
>  				e.ip[1] = htonl(ip2);
> -				ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
> -								&e.cidr[1]);
> +				ip2 = ip_set_range_to_cidr(ip2, ip2_to,
> +							   &e.cidr[1]);
>  				ret = adtfn(set, &e, &ext, &ext, flags);
>  				if (ret && !ip_set_eexist(ret, flags))
>  					return ret;
>  
>  				ret = 0;
> -				ip2 = ip2_last + 1;
> -			}
> +			} while (ip2++ < ip2_to);
> +			ip2 = ip2_from;
>  		}
> -		ip = ip_last + 1;
> -	}
> +		p = port;
> +	} while (ip++ < ip_to);
>  	return ret;
>  }
>  
> 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20190222/ddf6e3e4/attachment.sig>


More information about the kernel-team mailing list