Commit d57609fa authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

1) Use signed integer in ipv6_skip_exthdr() called from nf_confirm().
   Reported by static analysis tooling, patch from Florian Westphal.

2) Missing set type checks in nf_tables: Validate that set declaration
   matches the an existing set type, otherwise bail out with EEXIST.
   Currently, nf_tables silently accepts the re-declaration with a
   different type but it bails out later with EINVAL when the user adds
   entries to the set. This fix is relatively large because it requires
   two preparation patches that are included in this batch.

3) Do not ignore updates of timeout and gc_interval parameters in
   existing sets.

4) Fix a hang when 0/0 subnets is added to a hash:net,port,net type of
   ipset. Except hash:net,port,net and hash:net,iface, the set types don't
   support 0/0 and the auxiliary functions rely on this fact. So 0/0 needs
   a special handling in hash:net,port,net which was missing (hash:net,iface
   was not affected by this bug), from Jozsef Kadlecsik.

5) When adding/deleting large number of elements in one step in ipset,
   it can take a reasonable amount of time and can result in soft lockup
   errors. This patch is a complete rework of the previous version in order
   to use a smaller internal batch limit and at the same time removing
   the external hard limit to add arbitrary number of elements in one step.
   Also from Jozsef Kadlecsik.

Except for patch #1, which fixes a bug introduced in the previous net-next
development cycle, anything else has been broken for several releases.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 588ab2dc 5e29dc36
...@@ -197,7 +197,7 @@ struct ip_set_region { ...@@ -197,7 +197,7 @@ struct ip_set_region {
}; };
/* Max range where every element is added/deleted in one step */ /* Max range where every element is added/deleted in one step */
#define IPSET_MAX_RANGE (1<<20) #define IPSET_MAX_RANGE (1<<14)
/* The max revision number supported by any set type + 1 */ /* The max revision number supported by any set type + 1 */
#define IPSET_REVISION_MAX 9 #define IPSET_REVISION_MAX 9
......
...@@ -312,17 +312,29 @@ struct nft_set_iter { ...@@ -312,17 +312,29 @@ struct nft_set_iter {
/** /**
* struct nft_set_desc - description of set elements * struct nft_set_desc - description of set elements
* *
* @ktype: key type
* @klen: key length * @klen: key length
* @dtype: data type
* @dlen: data length * @dlen: data length
* @objtype: object type
* @flags: flags
* @size: number of set elements * @size: number of set elements
* @policy: set policy
* @gc_int: garbage collector interval
* @field_len: length of each field in concatenation, bytes * @field_len: length of each field in concatenation, bytes
* @field_count: number of concatenated fields in element * @field_count: number of concatenated fields in element
* @expr: set must support for expressions * @expr: set must support for expressions
*/ */
struct nft_set_desc { struct nft_set_desc {
u32 ktype;
unsigned int klen; unsigned int klen;
u32 dtype;
unsigned int dlen; unsigned int dlen;
u32 objtype;
unsigned int size; unsigned int size;
u32 policy;
u32 gc_int;
u64 timeout;
u8 field_len[NFT_REG32_COUNT]; u8 field_len[NFT_REG32_COUNT];
u8 field_count; u8 field_count;
bool expr; bool expr;
...@@ -585,7 +597,9 @@ void *nft_set_catchall_gc(const struct nft_set *set); ...@@ -585,7 +597,9 @@ void *nft_set_catchall_gc(const struct nft_set *set);
static inline unsigned long nft_set_gc_interval(const struct nft_set *set) static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
{ {
return set->gc_int ? msecs_to_jiffies(set->gc_int) : HZ; u32 gc_int = READ_ONCE(set->gc_int);
return gc_int ? msecs_to_jiffies(gc_int) : HZ;
} }
/** /**
...@@ -1558,6 +1572,9 @@ struct nft_trans_rule { ...@@ -1558,6 +1572,9 @@ struct nft_trans_rule {
struct nft_trans_set { struct nft_trans_set {
struct nft_set *set; struct nft_set *set;
u32 set_id; u32 set_id;
u32 gc_int;
u64 timeout;
bool update;
bool bound; bool bound;
}; };
...@@ -1567,6 +1584,12 @@ struct nft_trans_set { ...@@ -1567,6 +1584,12 @@ struct nft_trans_set {
(((struct nft_trans_set *)trans->data)->set_id) (((struct nft_trans_set *)trans->data)->set_id)
#define nft_trans_set_bound(trans) \ #define nft_trans_set_bound(trans) \
(((struct nft_trans_set *)trans->data)->bound) (((struct nft_trans_set *)trans->data)->bound)
#define nft_trans_set_update(trans) \
(((struct nft_trans_set *)trans->data)->update)
#define nft_trans_set_timeout(trans) \
(((struct nft_trans_set *)trans->data)->timeout)
#define nft_trans_set_gc_int(trans) \
(((struct nft_trans_set *)trans->data)->gc_int)
struct nft_trans_chain { struct nft_trans_chain {
bool update; bool update;
......
...@@ -1698,9 +1698,10 @@ call_ad(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1698,9 +1698,10 @@ call_ad(struct net *net, struct sock *ctnl, struct sk_buff *skb,
ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried); ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
ip_set_unlock(set); ip_set_unlock(set);
retried = true; retried = true;
} while (ret == -EAGAIN && } while (ret == -ERANGE ||
set->variant->resize && (ret == -EAGAIN &&
(ret = set->variant->resize(set, retried)) == 0); set->variant->resize &&
(ret = set->variant->resize(set, retried)) == 0));
if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
return 0; return 0;
......
...@@ -100,11 +100,11 @@ static int ...@@ -100,11 +100,11 @@ static int
hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
const struct hash_ip4 *h = set->data; struct hash_ip4 *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ip4_elem e = { 0 }; struct hash_ip4_elem e = { 0 };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip = 0, ip_to = 0, hosts; u32 ip = 0, ip_to = 0, hosts, i = 0;
int ret = 0; int ret = 0;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -149,14 +149,14 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -149,14 +149,14 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
/* 64bit division is not allowed on 32bit */
if (((u64)ip_to - ip + 1) >> (32 - h->netmask) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
for (; ip <= ip_to;) { for (; ip <= ip_to; i++) {
e.ip = htonl(ip); e.ip = htonl(ip);
if (i > IPSET_MAX_RANGE) {
hash_ip4_data_next(&h->next, &e);
return -ERANGE;
}
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
......
...@@ -97,11 +97,11 @@ static int ...@@ -97,11 +97,11 @@ static int
hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
const struct hash_ipmark4 *h = set->data; struct hash_ipmark4 *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipmark4_elem e = { }; struct hash_ipmark4_elem e = { };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip, ip_to = 0; u32 ip, ip_to = 0, i = 0;
int ret; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -148,13 +148,14 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -148,13 +148,14 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
ip_set_mask_from_to(ip, ip_to, cidr); ip_set_mask_from_to(ip, ip_to, cidr);
} }
if (((u64)ip_to - ip + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
for (; ip <= ip_to; ip++) { for (; ip <= ip_to; ip++, i++) {
e.ip = htonl(ip); e.ip = htonl(ip);
if (i > IPSET_MAX_RANGE) {
hash_ipmark4_data_next(&h->next, &e);
return -ERANGE;
}
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
......
...@@ -112,11 +112,11 @@ static int ...@@ -112,11 +112,11 @@ static int
hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
const struct hash_ipport4 *h = set->data; struct hash_ipport4 *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport4_elem e = { .ip = 0 }; struct hash_ipport4_elem e = { .ip = 0 };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip, ip_to = 0, p = 0, port, port_to; u32 ip, ip_to = 0, p = 0, port, port_to, i = 0;
bool with_ports = false; bool with_ports = false;
int ret; int ret;
...@@ -184,17 +184,18 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -184,17 +184,18 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
} }
if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
for (; ip <= ip_to; ip++) { for (; ip <= ip_to; ip++) {
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port) p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port; : port;
for (; p <= port_to; p++) { for (; p <= port_to; p++, i++) {
e.ip = htonl(ip); e.ip = htonl(ip);
e.port = htons(p); e.port = htons(p);
if (i > IPSET_MAX_RANGE) {
hash_ipport4_data_next(&h->next, &e);
return -ERANGE;
}
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
......
...@@ -108,11 +108,11 @@ static int ...@@ -108,11 +108,11 @@ static int
hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
const struct hash_ipportip4 *h = set->data; struct hash_ipportip4 *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip4_elem e = { .ip = 0 }; struct hash_ipportip4_elem e = { .ip = 0 };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip, ip_to = 0, p = 0, port, port_to; u32 ip, ip_to = 0, p = 0, port, port_to, i = 0;
bool with_ports = false; bool with_ports = false;
int ret; int ret;
...@@ -180,17 +180,18 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -180,17 +180,18 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
} }
if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
for (; ip <= ip_to; ip++) { for (; ip <= ip_to; ip++) {
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port) p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port; : port;
for (; p <= port_to; p++) { for (; p <= port_to; p++, i++) {
e.ip = htonl(ip); e.ip = htonl(ip);
e.port = htons(p); e.port = htons(p);
if (i > IPSET_MAX_RANGE) {
hash_ipportip4_data_next(&h->next, &e);
return -ERANGE;
}
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
......
...@@ -160,12 +160,12 @@ static int ...@@ -160,12 +160,12 @@ static int
hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
const struct hash_ipportnet4 *h = set->data; struct hash_ipportnet4 *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 }; struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip = 0, ip_to = 0, p = 0, port, port_to; u32 ip = 0, ip_to = 0, p = 0, port, port_to;
u32 ip2_from = 0, ip2_to = 0, ip2; u32 ip2_from = 0, ip2_to = 0, ip2, i = 0;
bool with_ports = false; bool with_ports = false;
u8 cidr; u8 cidr;
int ret; int ret;
...@@ -253,9 +253,6 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -253,9 +253,6 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
} }
if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
ip2_to = ip2_from; ip2_to = ip2_from;
if (tb[IPSET_ATTR_IP2_TO]) { if (tb[IPSET_ATTR_IP2_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
...@@ -282,9 +279,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -282,9 +279,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
for (; p <= port_to; p++) { for (; p <= port_to; p++) {
e.port = htons(p); e.port = htons(p);
do { do {
i++;
e.ip2 = htonl(ip2); e.ip2 = htonl(ip2);
ip2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr); ip2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr);
e.cidr = cidr - 1; e.cidr = cidr - 1;
if (i > IPSET_MAX_RANGE) {
hash_ipportnet4_data_next(&h->next,
&e);
return -ERANGE;
}
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
......
...@@ -136,11 +136,11 @@ static int ...@@ -136,11 +136,11 @@ static int
hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
const struct hash_net4 *h = set->data; struct hash_net4 *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net4_elem e = { .cidr = HOST_MASK }; struct hash_net4_elem e = { .cidr = HOST_MASK };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip = 0, ip_to = 0, ipn, n = 0; u32 ip = 0, ip_to = 0, i = 0;
int ret; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -188,19 +188,16 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -188,19 +188,16 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
if (ip + UINT_MAX == ip_to) if (ip + UINT_MAX == ip_to)
return -IPSET_ERR_HASH_RANGE; return -IPSET_ERR_HASH_RANGE;
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr);
n++;
} while (ipn++ < ip_to);
if (n > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
do { do {
i++;
e.ip = htonl(ip); e.ip = htonl(ip);
if (i > IPSET_MAX_RANGE) {
hash_net4_data_next(&h->next, &e);
return -ERANGE;
}
ip = 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); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
......
...@@ -202,7 +202,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -202,7 +202,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 }; struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip = 0, ip_to = 0, ipn, n = 0; u32 ip = 0, ip_to = 0, i = 0;
int ret; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -256,19 +256,16 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -256,19 +256,16 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
} else { } else {
ip_set_mask_from_to(ip, ip_to, e.cidr); ip_set_mask_from_to(ip, ip_to, e.cidr);
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr);
n++;
} while (ipn++ < ip_to);
if (n > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
do { do {
i++;
e.ip = htonl(ip); e.ip = htonl(ip);
if (i > IPSET_MAX_RANGE) {
hash_netiface4_data_next(&h->next, &e);
return -ERANGE;
}
ip = 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); ret = adtfn(set, &e, &ext, &ext, flags);
......
...@@ -166,13 +166,12 @@ static int ...@@ -166,13 +166,12 @@ static int
hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
const struct hash_netnet4 *h = set->data; struct hash_netnet4 *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netnet4_elem e = { }; struct hash_netnet4_elem e = { };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip = 0, ip_to = 0; u32 ip = 0, ip_to = 0;
u32 ip2 = 0, ip2_from = 0, ip2_to = 0, ipn; u32 ip2 = 0, ip2_from = 0, ip2_to = 0, i = 0;
u64 n = 0, m = 0;
int ret; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -248,19 +247,6 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -248,19 +247,6 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
} else { } else {
ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr[0]);
n++;
} while (ipn++ < ip_to);
ipn = ip2_from;
do {
ipn = ip_set_range_to_cidr(ipn, ip2_to, &e.cidr[1]);
m++;
} while (ipn++ < ip2_to);
if (n*m > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) { if (retried) {
ip = ntohl(h->next.ip[0]); ip = ntohl(h->next.ip[0]);
...@@ -273,7 +259,12 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -273,7 +259,12 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
e.ip[0] = htonl(ip); e.ip[0] = htonl(ip);
ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]); ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
do { do {
i++;
e.ip[1] = htonl(ip2); e.ip[1] = htonl(ip2);
if (i > IPSET_MAX_RANGE) {
hash_netnet4_data_next(&h->next, &e);
return -ERANGE;
}
ip2 = 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); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
......
...@@ -154,12 +154,11 @@ static int ...@@ -154,12 +154,11 @@ static int
hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
const struct hash_netport4 *h = set->data; struct hash_netport4 *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 }; struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 port, port_to, p = 0, ip = 0, ip_to = 0, ipn; u32 port, port_to, p = 0, ip = 0, ip_to = 0, i = 0;
u64 n = 0;
bool with_ports = false; bool with_ports = false;
u8 cidr; u8 cidr;
int ret; int ret;
...@@ -236,14 +235,6 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -236,14 +235,6 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
} else { } else {
ip_set_mask_from_to(ip, ip_to, e.cidr + 1); ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &cidr);
n++;
} while (ipn++ < ip_to);
if (n*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) { if (retried) {
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
...@@ -255,8 +246,12 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -255,8 +246,12 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
e.ip = htonl(ip); e.ip = htonl(ip);
ip = ip_set_range_to_cidr(ip, ip_to, &cidr); ip = ip_set_range_to_cidr(ip, ip_to, &cidr);
e.cidr = cidr - 1; e.cidr = cidr - 1;
for (; p <= port_to; p++) { for (; p <= port_to; p++, i++) {
e.port = htons(p); e.port = htons(p);
if (i > IPSET_MAX_RANGE) {
hash_netport4_data_next(&h->next, &e);
return -ERANGE;
}
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
......
...@@ -173,17 +173,26 @@ hash_netportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -173,17 +173,26 @@ hash_netportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
} }
static u32
hash_netportnet4_range_to_cidr(u32 from, u32 to, u8 *cidr)
{
if (from == 0 && to == UINT_MAX) {
*cidr = 0;
return to;
}
return ip_set_range_to_cidr(from, to, cidr);
}
static int static int
hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{ {
const struct hash_netportnet4 *h = set->data; struct hash_netportnet4 *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netportnet4_elem e = { }; struct hash_netportnet4_elem e = { };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip = 0, ip_to = 0, p = 0, port, port_to; u32 ip = 0, ip_to = 0, p = 0, port, port_to;
u32 ip2_from = 0, ip2_to = 0, ip2, ipn; u32 ip2_from = 0, ip2_to = 0, ip2, i = 0;
u64 n = 0, m = 0;
bool with_ports = false; bool with_ports = false;
int ret; int ret;
...@@ -285,19 +294,6 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -285,19 +294,6 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
} else { } else {
ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr[0]);
n++;
} while (ipn++ < ip_to);
ipn = ip2_from;
do {
ipn = ip_set_range_to_cidr(ipn, ip2_to, &e.cidr[1]);
m++;
} while (ipn++ < ip2_to);
if (n*m*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) { if (retried) {
ip = ntohl(h->next.ip[0]); ip = ntohl(h->next.ip[0]);
...@@ -310,13 +306,19 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -310,13 +306,19 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
do { do {
e.ip[0] = htonl(ip); e.ip[0] = htonl(ip);
ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]); ip = hash_netportnet4_range_to_cidr(ip, ip_to, &e.cidr[0]);
for (; p <= port_to; p++) { for (; p <= port_to; p++) {
e.port = htons(p); e.port = htons(p);
do { do {
i++;
e.ip[1] = htonl(ip2); e.ip[1] = htonl(ip2);
ip2 = ip_set_range_to_cidr(ip2, ip2_to, if (i > IPSET_MAX_RANGE) {
&e.cidr[1]); hash_netportnet4_data_next(&h->next,
&e);
return -ERANGE;
}
ip2 = hash_netportnet4_range_to_cidr(ip2,
ip2_to, &e.cidr[1]);
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
......
...@@ -141,6 +141,7 @@ unsigned int nf_confirm(void *priv, ...@@ -141,6 +141,7 @@ unsigned int nf_confirm(void *priv,
struct nf_conn *ct; struct nf_conn *ct;
bool seqadj_needed; bool seqadj_needed;
__be16 frag_off; __be16 frag_off;
int start;
u8 pnum; u8 pnum;
ct = nf_ct_get(skb, &ctinfo); ct = nf_ct_get(skb, &ctinfo);
...@@ -163,9 +164,11 @@ unsigned int nf_confirm(void *priv, ...@@ -163,9 +164,11 @@ unsigned int nf_confirm(void *priv,
break; break;
case NFPROTO_IPV6: case NFPROTO_IPV6:
pnum = ipv6_hdr(skb)->nexthdr; pnum = ipv6_hdr(skb)->nexthdr;
protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, &frag_off); start = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, &frag_off);
if (protoff < 0 || (frag_off & htons(~0x7)) != 0) if (start < 0 || (frag_off & htons(~0x7)) != 0)
return nf_conntrack_confirm(skb); return nf_conntrack_confirm(skb);
protoff = start;
break; break;
default: default:
return nf_conntrack_confirm(skb); return nf_conntrack_confirm(skb);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment