diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
index 6115bf1ff6f0..1912fc66147c 100644
--- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
@@ -218,7 +218,8 @@ int nf_nat_icmp_reply_translation(struct sk_buff *skb,
return 1;
l4proto = __nf_nat_l4proto_find(NFPROTO_IPV4, inside->ip.protocol);
- if (!nf_nat_ipv4_manip_pkt(skb, hdrlen + sizeof(inside->icmp),
+ if (!l4proto ||
+ !nf_nat_ipv4_manip_pkt(skb, hdrlen + sizeof(inside->icmp),
l4proto, &ct->tuplehash[!dir].tuple, !manip))
return 0;
@@ -234,7 +235,8 @@ int nf_nat_icmp_reply_translation(struct sk_buff *skb,
/* Change outer to look like the reply to an incoming packet */
nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
l4proto = __nf_nat_l4proto_find(NFPROTO_IPV4, 0);
- if (!nf_nat_ipv4_manip_pkt(skb, 0, l4proto, &target, manip))
+ if (!l4proto ||
+ !nf_nat_ipv4_manip_pkt(skb, 0, l4proto, &target, manip))
return 0;
return 1;
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
index ca6d38698b1a..a72840baf27b 100644
--- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
@@ -228,7 +228,8 @@ int nf_nat_icmpv6_reply_translation(struct sk_buff *skb,
return 1;
l4proto = __nf_nat_l4proto_find(NFPROTO_IPV6, inside->ip6.nexthdr);
- if (!nf_nat_ipv6_manip_pkt(skb, hdrlen + sizeof(inside->icmp6),
+ if (!l4proto ||
+ !nf_nat_ipv6_manip_pkt(skb, hdrlen + sizeof(inside->icmp6),
l4proto, &ct->tuplehash[!dir].tuple, !manip))
return 0;
@@ -245,7 +246,7 @@ int nf_nat_icmpv6_reply_translation(struct sk_buff *skb,
nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
l4proto = __nf_nat_l4proto_find(NFPROTO_IPV6, IPPROTO_ICMPV6);
- if (!nf_nat_ipv6_manip_pkt(skb, 0, l4proto, &target, manip))
+ if (!l4proto || !nf_nat_ipv6_manip_pkt(skb, 0, l4proto, &target, manip))
return 0;
return 1;
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 2268b10a9dcf..d28185f38955 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -64,12 +64,16 @@ struct nat_net {
inline const struct nf_nat_l3proto *
__nf_nat_l3proto_find(u8 family)
{
+ if (family >= NFPROTO_NUMPROTO)
+ return NULL;
return rcu_dereference(nf_nat_l3protos[family]);
}
inline const struct nf_nat_l4proto *
__nf_nat_l4proto_find(u8 family, u8 protonum)
{
+ if (family >= NFPROTO_NUMPROTO)
+ return NULL;
return rcu_dereference(nf_nat_l4protos[family][protonum]);
}
EXPORT_SYMBOL_GPL(__nf_nat_l4proto_find);@@ -317,7 +321,7 @@ find_best_ips_proto(const struct nf_conntrack_zone *zone,
* range. It might not be possible to get a unique tuple, but we try.
* At worst (or if we race), we will end up with a final duplicate in
* __ip_conntrack_confirm and drop the packet. */
-static void
+static int
get_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *orig_tuple,
const struct nf_nat_range2 *range,
@@ -328,13 +332,22 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_l3proto *l3proto;
const struct nf_nat_l4proto *l4proto;
struct net *net = nf_ct_net(ct);
+ int ret = 0;
zone = nf_ct_zone(ct);
rcu_read_lock();
l3proto = __nf_nat_l3proto_find(orig_tuple->src.l3num);
+ if (!l3proto) {
+ ret = -EINVAL;
+ goto out;
+ }
l4proto = __nf_nat_l4proto_find(orig_tuple->src.l3num,
orig_tuple->dst.protonum);
+ if (!l4proto) {
+ ret = -EINVAL;
+ goto out;
+ }
/* 1) If this srcip/proto/src-proto-part is currently mapped,
* and that same mapping gives a unique tuple within the given@@ -387,6 +400,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
l4proto->unique_tuple(l3proto, tuple, range, maniptype, ct);
out:
rcu_read_unlock();
+ return ret;
}
struct nf_conn_nat *nf_ct_nat_ext_add(struct nf_conn *ct)
@@ -409,6 +423,7 @@ nf_nat_setup_info(struct nf_conn *ct,
{
struct net *net = nf_ct_net(ct);
struct nf_conntrack_tuple curr_tuple, new_tuple;
+ int err;
/* Can't setup nat info for confirmed ct. */
if (nf_ct_is_confirmed(ct))@@ -428,7 +443,9 @@ nf_nat_setup_info(struct nf_conn *ct,
nf_ct_invert_tuplepr(&curr_tuple,
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
- get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype);
+ err = get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype);
+ if (err < 0)
+ return NF_DROP;
if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) {
struct nf_conntrack_tuple reply;@@ -509,8 +526,12 @@ static unsigned int nf_nat_manip_pkt(struct sk_buff *skb, struct nf_conn *ct,
nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
l3proto = __nf_nat_l3proto_find(target.src.l3num);
+ if (!l3proto)
+ return NF_DROP;
l4proto = __nf_nat_l4proto_find(target.src.l3num,
target.dst.protonum);
+ if (!l4proto)
+ return NF_DROP;
if (!l3proto->manip_pkt(skb, 0, l4proto, &target, mtype))
return NF_DROP;
@@ -816,6 +837,8 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr,
return err;
l4proto = __nf_nat_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
+ if (!l4proto)
+ return -EINVAL;
if (l4proto->nlattr_to_range)
err = l4proto->nlattr_to_range(tb, range);
diff --git a/net/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c
index 99606baedda4..6f694444137e 100644
--- a/net/netfilter/nf_nat_helper.c
+++ b/net/netfilter/nf_nat_helper.c
@@ -121,6 +121,8 @@ bool __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
datalen = skb->len - protoff;
l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
+ if (!l3proto)
+ return false;
l3proto->csum_recalc(skb, IPPROTO_TCP, tcph, &tcph->check,
datalen, oldlen);
@@ -179,6 +181,8 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
return true;
l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
+ if (!l3proto)
+ return false;
l3proto->csum_recalc(skb, IPPROTO_UDP, udph, &udph->check,
datalen, oldlen);
--
2.28.0.rc0.142.g3c755180ce-goog