Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Browse files Browse the repository at this point in the history
Pablo Neira Ayuso says:

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

The following patchset contains Netfilter fixes for your net tree,
they are:

1) Fix OOM that syskaller triggers with ipt_replace.size = -1 and
   IPT_SO_SET_REPLACE socket option, from Dmitry Vyukov.

2) Check for too long extension name in xt_request_find_{match|target}
   that result in out-of-bound reads, from Eric Dumazet.

3) Fix memory exhaustion bug in ipset hash:*net* types when adding ranges
   that look like x.x.x.x-255.255.255.255, from Jozsef Kadlecsik.

4) Fix pointer leaks to userspace in x_tables, from Dmitry Vyukov.

5) Insufficient sanity checks in clusterip_tg_check(), also from Dmitry.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Feb 1, 2018
2 parents 7973bfd + 3f34cfa commit b9a4072
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 99 deletions.
14 changes: 4 additions & 10 deletions net/ipv4/ip_sockglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -1255,11 +1255,8 @@ int ip_setsockopt(struct sock *sk, int level,
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
optname != IP_IPSEC_POLICY &&
optname != IP_XFRM_POLICY &&
!ip_mroute_opt(optname)) {
lock_sock(sk);
!ip_mroute_opt(optname))
err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
release_sock(sk);
}
#endif
return err;
}
Expand All @@ -1284,12 +1281,9 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname,
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
optname != IP_IPSEC_POLICY &&
optname != IP_XFRM_POLICY &&
!ip_mroute_opt(optname)) {
lock_sock(sk);
err = compat_nf_setsockopt(sk, PF_INET, optname,
optval, optlen);
release_sock(sk);
}
!ip_mroute_opt(optname))
err = compat_nf_setsockopt(sk, PF_INET, optname, optval,
optlen);
#endif
return err;
}
Expand Down
16 changes: 13 additions & 3 deletions net/ipv4/netfilter/ipt_CLUSTERIP.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
const struct ipt_entry *e = par->entryinfo;
struct clusterip_config *config;
int ret;
int ret, i;

if (par->nft_compat) {
pr_err("cannot use CLUSTERIP target from nftables compat\n");
Expand All @@ -450,8 +450,18 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
pr_info("Please specify destination IP\n");
return -EINVAL;
}

/* FIXME: further sanity checks */
if (cipinfo->num_local_nodes > ARRAY_SIZE(cipinfo->local_nodes)) {
pr_info("bad num_local_nodes %u\n", cipinfo->num_local_nodes);
return -EINVAL;
}
for (i = 0; i < cipinfo->num_local_nodes; i++) {
if (cipinfo->local_nodes[i] - 1 >=
sizeof(config->local_nodes) * 8) {
pr_info("bad local_nodes[%d] %u\n",
i, cipinfo->local_nodes[i]);
return -EINVAL;
}
}

config = clusterip_config_find_get(par->net, e->ip.dst.s_addr, 1);
if (!config) {
Expand Down
6 changes: 5 additions & 1 deletion net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,19 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
struct nf_conntrack_tuple tuple;

memset(&tuple, 0, sizeof(tuple));

lock_sock(sk);
tuple.src.u3.ip = inet->inet_rcv_saddr;
tuple.src.u.tcp.port = inet->inet_sport;
tuple.dst.u3.ip = inet->inet_daddr;
tuple.dst.u.tcp.port = inet->inet_dport;
tuple.src.l3num = PF_INET;
tuple.dst.protonum = sk->sk_protocol;
release_sock(sk);

/* We only do TCP and SCTP at the moment: is there a better way? */
if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) {
if (tuple.dst.protonum != IPPROTO_TCP &&
tuple.dst.protonum != IPPROTO_SCTP) {
pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n");
return -ENOPROTOOPT;
}
Expand Down
17 changes: 5 additions & 12 deletions net/ipv6/ipv6_sockglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -923,12 +923,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
optname != IPV6_XFRM_POLICY) {
lock_sock(sk);
err = nf_setsockopt(sk, PF_INET6, optname, optval,
optlen);
release_sock(sk);
}
optname != IPV6_XFRM_POLICY)
err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen);
#endif
return err;
}
Expand Down Expand Up @@ -958,12 +954,9 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
optname != IPV6_XFRM_POLICY) {
lock_sock(sk);
err = compat_nf_setsockopt(sk, PF_INET6, optname,
optval, optlen);
release_sock(sk);
}
optname != IPV6_XFRM_POLICY)
err = compat_nf_setsockopt(sk, PF_INET6, optname, optval,
optlen);
#endif
return err;
}
Expand Down
18 changes: 12 additions & 6 deletions net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,20 +221,27 @@ static const struct nf_hook_ops ipv6_conntrack_ops[] = {
static int
ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
{
const struct inet_sock *inet = inet_sk(sk);
struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
const struct ipv6_pinfo *inet6 = inet6_sk(sk);
const struct inet_sock *inet = inet_sk(sk);
const struct nf_conntrack_tuple_hash *h;
struct sockaddr_in6 sin6;
struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
struct nf_conn *ct;
__be32 flow_label;
int bound_dev_if;

lock_sock(sk);
tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
tuple.src.u.tcp.port = inet->inet_sport;
tuple.dst.u3.in6 = sk->sk_v6_daddr;
tuple.dst.u.tcp.port = inet->inet_dport;
tuple.dst.protonum = sk->sk_protocol;
bound_dev_if = sk->sk_bound_dev_if;
flow_label = inet6->flow_label;
release_sock(sk);

if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP)
if (tuple.dst.protonum != IPPROTO_TCP &&
tuple.dst.protonum != IPPROTO_SCTP)
return -ENOPROTOOPT;

if (*len < 0 || (unsigned int) *len < sizeof(sin6))
Expand All @@ -252,14 +259,13 @@ ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)

sin6.sin6_family = AF_INET6;
sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK;
sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
memcpy(&sin6.sin6_addr,
&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
sizeof(sin6.sin6_addr));

nf_ct_put(ct);
sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr,
sk->sk_bound_dev_if);
sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
}

Expand Down
26 changes: 13 additions & 13 deletions net/netfilter/ipset/ip_set_hash_ipportnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -269,32 +269,32 @@ 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);

if (ret && !ip_set_eexist(ret, flags))
return ret;

ret = 0;
ip2 = ip2_last + 1;
}
} while (ip2++ < ip2_to);
ip2 = ip2_from;
}
p = port;
}
return ret;
}
Expand Down
9 changes: 4 additions & 5 deletions net/netfilter/ipset/ip_set_hash_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down Expand Up @@ -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;
}

Expand Down
9 changes: 4 additions & 5 deletions net/netfilter/ipset/ip_set_hash_netiface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down Expand Up @@ -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;
}

Expand Down
28 changes: 14 additions & 14 deletions net/netfilter/ipset/ip_set_hash_netnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down Expand Up @@ -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;
}

Expand Down
19 changes: 10 additions & 9 deletions net/netfilter/ipset/ip_set_hash_netport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
Loading

0 comments on commit b9a4072

Please sign in to comment.