Commit 61c5923a authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

====================
The following patchset contains Netfilter fixes for you net tree,
mostly targeted to ipset, they are:

* Fix ICMPv6 NAT due to wrong comparison, code instead of type, from
  Phil Oester.

* Fix RCU race in conntrack extensions release path, from Michal Kubecek.

* Fix missing inversion in the userspace ipset test command match if
  the nomatch option is specified, from Jozsef Kadlecsik.

* Skip layer 4 protocol matching in ipset in case of IPv6 fragments,
  also from Jozsef Kadlecsik.

* Fix sequence adjustment in nfnetlink_queue due to using the netlink
  skb instead of the network skb, from Gao feng.

* Make sure we cannot swap of sets with different layer 3 family in
  ipset, from Jozsef Kadlecsik.

* Fix possible bogus matching in ipset if hash sets with net elements
  are used, from Oliver Smith.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2936b6ab 0a0d80eb
...@@ -296,10 +296,12 @@ ip_set_eexist(int ret, u32 flags) ...@@ -296,10 +296,12 @@ ip_set_eexist(int ret, u32 flags)
/* Match elements marked with nomatch */ /* Match elements marked with nomatch */
static inline bool static inline bool
ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt) ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt, struct ip_set *set)
{ {
return adt == IPSET_TEST && return adt == IPSET_TEST &&
ret == -ENOTEMPTY && ((flags >> 16) & IPSET_FLAG_NOMATCH); (set->type->features & IPSET_TYPE_NOMATCH) &&
((flags >> 16) & IPSET_FLAG_NOMATCH) &&
(ret > 0 || ret == -ENOTEMPTY);
} }
/* Check the NLA_F_NET_BYTEORDER flag */ /* Check the NLA_F_NET_BYTEORDER flag */
......
...@@ -86,7 +86,7 @@ static inline void nf_ct_ext_destroy(struct nf_conn *ct) ...@@ -86,7 +86,7 @@ static inline void nf_ct_ext_destroy(struct nf_conn *ct)
static inline void nf_ct_ext_free(struct nf_conn *ct) static inline void nf_ct_ext_free(struct nf_conn *ct)
{ {
if (ct->ext) if (ct->ext)
kfree(ct->ext); kfree_rcu(ct->ext, rcu);
} }
/* Add this type, returns pointer to data or NULL. */ /* Add this type, returns pointer to data or NULL. */
......
...@@ -69,8 +69,8 @@ icmpv6_manip_pkt(struct sk_buff *skb, ...@@ -69,8 +69,8 @@ icmpv6_manip_pkt(struct sk_buff *skb,
hdr = (struct icmp6hdr *)(skb->data + hdroff); hdr = (struct icmp6hdr *)(skb->data + hdroff);
l3proto->csum_update(skb, iphdroff, &hdr->icmp6_cksum, l3proto->csum_update(skb, iphdroff, &hdr->icmp6_cksum,
tuple, maniptype); tuple, maniptype);
if (hdr->icmp6_code == ICMPV6_ECHO_REQUEST || if (hdr->icmp6_type == ICMPV6_ECHO_REQUEST ||
hdr->icmp6_code == ICMPV6_ECHO_REPLY) { hdr->icmp6_type == ICMPV6_ECHO_REPLY) {
inet_proto_csum_replace2(&hdr->icmp6_cksum, skb, inet_proto_csum_replace2(&hdr->icmp6_cksum, skb,
hdr->icmp6_identifier, hdr->icmp6_identifier,
tuple->src.u.icmp.id, 0); tuple->src.u.icmp.id, 0);
......
...@@ -1052,7 +1052,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, ...@@ -1052,7 +1052,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
* Not an artificial restriction anymore, as we must prevent * Not an artificial restriction anymore, as we must prevent
* possible loops created by swapping in setlist type of sets. */ * possible loops created by swapping in setlist type of sets. */
if (!(from->type->features == to->type->features && if (!(from->type->features == to->type->features &&
from->type->family == to->type->family)) from->family == to->family))
return -IPSET_ERR_TYPE_MISMATCH; return -IPSET_ERR_TYPE_MISMATCH;
strncpy(from_name, from->name, IPSET_MAXNAMELEN); strncpy(from_name, from->name, IPSET_MAXNAMELEN);
...@@ -1489,8 +1489,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb, ...@@ -1489,8 +1489,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
if (ret == -EAGAIN) if (ret == -EAGAIN)
ret = 1; ret = 1;
return (ret < 0 && ret != -ENOTEMPTY) ? ret : return ret > 0 ? 0 : -IPSET_ERR_EXIST;
ret > 0 ? 0 : -IPSET_ERR_EXIST;
} }
/* Get headed data of a set */ /* Get headed data of a set */
......
...@@ -116,12 +116,12 @@ ip_set_get_ip6_port(const struct sk_buff *skb, bool src, ...@@ -116,12 +116,12 @@ ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
{ {
int protoff; int protoff;
u8 nexthdr; u8 nexthdr;
__be16 frag_off; __be16 frag_off = 0;
nexthdr = ipv6_hdr(skb)->nexthdr; nexthdr = ipv6_hdr(skb)->nexthdr;
protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
&frag_off); &frag_off);
if (protoff < 0) if (protoff < 0 || (frag_off & htons(~0x7)) != 0)
return false; return false;
return get_port(skb, nexthdr, protoff, src, port, proto); return get_port(skb, nexthdr, protoff, src, port, proto);
......
...@@ -325,18 +325,22 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length) ...@@ -325,18 +325,22 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
static void static void
mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length) mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
{ {
u8 i, j; u8 i, j, net_end = nets_length - 1;
for (i = 0; i < nets_length - 1 && h->nets[i].cidr != cidr; i++) for (i = 0; i < nets_length; i++) {
; if (h->nets[i].cidr != cidr)
h->nets[i].nets--; continue;
if (h->nets[i].nets > 1 || i == net_end ||
if (h->nets[i].nets != 0) h->nets[i + 1].nets == 0) {
return; h->nets[i].nets--;
return;
for (j = i; j < nets_length - 1 && h->nets[j].nets; j++) { }
h->nets[j].cidr = h->nets[j + 1].cidr; for (j = i; j < net_end && h->nets[j].nets; j++) {
h->nets[j].nets = h->nets[j + 1].nets; h->nets[j].cidr = h->nets[j + 1].cidr;
h->nets[j].nets = h->nets[j + 1].nets;
}
h->nets[j].nets = 0;
return;
} }
} }
#endif #endif
......
...@@ -260,7 +260,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -260,7 +260,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
e.ip = htonl(ip); e.ip = htonl(ip);
e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1)); e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1));
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_enomatch(ret, flags, adt) ? 1 : return ip_set_enomatch(ret, flags, adt, set) ? -ret :
ip_set_eexist(ret, flags) ? 0 : ret; ip_set_eexist(ret, flags) ? 0 : ret;
} }
...@@ -544,7 +544,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -544,7 +544,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_enomatch(ret, flags, adt) ? 1 : return ip_set_enomatch(ret, flags, adt, set) ? -ret :
ip_set_eexist(ret, flags) ? 0 : ret; ip_set_eexist(ret, flags) ? 0 : ret;
} }
......
...@@ -199,7 +199,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -199,7 +199,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
e.ip = htonl(ip & ip_set_hostmask(e.cidr)); e.ip = htonl(ip & ip_set_hostmask(e.cidr));
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_enomatch(ret, flags, adt) ? 1 : return ip_set_enomatch(ret, flags, adt, set) ? -ret:
ip_set_eexist(ret, flags) ? 0 : ret; ip_set_eexist(ret, flags) ? 0 : ret;
} }
...@@ -396,7 +396,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -396,7 +396,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_enomatch(ret, flags, adt) ? 1 : return ip_set_enomatch(ret, flags, adt, set) ? -ret :
ip_set_eexist(ret, flags) ? 0 : ret; ip_set_eexist(ret, flags) ? 0 : ret;
} }
......
...@@ -368,7 +368,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -368,7 +368,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
e.ip = htonl(ip & ip_set_hostmask(e.cidr)); e.ip = htonl(ip & ip_set_hostmask(e.cidr));
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_enomatch(ret, flags, adt) ? 1 : return ip_set_enomatch(ret, flags, adt, set) ? -ret :
ip_set_eexist(ret, flags) ? 0 : ret; ip_set_eexist(ret, flags) ? 0 : ret;
} }
...@@ -634,7 +634,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -634,7 +634,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_enomatch(ret, flags, adt) ? 1 : return ip_set_enomatch(ret, flags, adt, set) ? -ret :
ip_set_eexist(ret, flags) ? 0 : ret; ip_set_eexist(ret, flags) ? 0 : ret;
} }
......
...@@ -244,7 +244,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -244,7 +244,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) { if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
e.ip = htonl(ip & ip_set_hostmask(e.cidr + 1)); e.ip = htonl(ip & ip_set_hostmask(e.cidr + 1));
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_enomatch(ret, flags, adt) ? 1 : return ip_set_enomatch(ret, flags, adt, set) ? -ret :
ip_set_eexist(ret, flags) ? 0 : ret; ip_set_eexist(ret, flags) ? 0 : ret;
} }
...@@ -489,7 +489,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -489,7 +489,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_enomatch(ret, flags, adt) ? 1 : return ip_set_enomatch(ret, flags, adt, set) ? -ret :
ip_set_eexist(ret, flags) ? 0 : ret; ip_set_eexist(ret, flags) ? 0 : ret;
} }
......
...@@ -1009,7 +1009,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, ...@@ -1009,7 +1009,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
verdict = NF_DROP; verdict = NF_DROP;
if (ct) if (ct)
nfqnl_ct_seq_adjust(skb, ct, ctinfo, diff); nfqnl_ct_seq_adjust(entry->skb, ct, ctinfo, diff);
} }
if (nfqa[NFQA_MARK]) if (nfqa[NFQA_MARK])
......
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