Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b8d9073 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Pablo Neira Ayuso
Browse files

netfilter: ipset: Fix wraparound in hash:*net* types



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: 48596a8d ("netfilter: ipset: Fix adding an IPv4 range containing more than 2^31 addresses")
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent da17c73b
Loading
Loading
Loading
Loading
+13 −13
Original line number Diff line number Diff line
@@ -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;
}
+4 −5
Original line number Diff line number Diff line
@@ -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;
}

+4 −5
Original line number Diff line number Diff line
@@ -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;
}

+14 −14
Original line number Diff line number Diff line
@@ -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;
}

+10 −9
Original line number Diff line number Diff line
@@ -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;
}

Loading