hulk inclusion category: bugfix bugzilla: NA CVE: NA
-------------------------------------------------
famliy can be passed from user space and will be out of range of nf_nat_l3protos or nf_nat_l4protos, so we need check the family when call __nf_nat_l3proto_find() or __nf_nat_l4proto_find().
nfnetlink_parse_nat_setup() need return EAGAIN, if __nf_nat_l3proto_find() returns null, so we return a error number to distinguish this case.
Signed-off-by: Yang Yingliang yangyingliang@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | 4 +++- net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 4 +++- net/netfilter/nf_nat_core.c | 21 ++++++++++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c index 6115bf1ff6f0..52e3f9c7bc69 100644 --- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c @@ -218,6 +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 (!l4proto) + return 1; if (!nf_nat_ipv4_manip_pkt(skb, hdrlen + sizeof(inside->icmp), l4proto, &ct->tuplehash[!dir].tuple, !manip)) return 0; @@ -234,7 +236,7 @@ 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..bf25263b2dcd 100644 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c @@ -228,6 +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 (!l4proto) + return 1; if (!nf_nat_ipv6_manip_pkt(skb, hdrlen + sizeof(inside->icmp6), l4proto, &ct->tuplehash[!dir].tuple, !manip)) return 0; @@ -245,7 +247,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..f1576e46ee2c 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -64,12 +64,18 @@ struct nat_net { inline const struct nf_nat_l3proto * __nf_nat_l3proto_find(u8 family) { + if (unlikely(family >= NFPROTO_NUMPROTO)) + return ERR_PTR(-EPROTONOSUPPORT); + return rcu_dereference(nf_nat_l3protos[family]); }
inline const struct nf_nat_l4proto * __nf_nat_l4proto_find(u8 family, u8 protonum) { + if (unlikely(family >= NFPROTO_NUMPROTO || nf_nat_l4protos[family] == NULL)) + return NULL; + return rcu_dereference(nf_nat_l4protos[family][protonum]); } EXPORT_SYMBOL_GPL(__nf_nat_l4proto_find); @@ -90,7 +96,7 @@ static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl)
family = nf_ct_l3num(ct); l3proto = __nf_nat_l3proto_find(family); - if (l3proto == NULL) + if (IS_ERR_OR_NULL(l3proto)) return;
dir = CTINFO2DIR(ctinfo); @@ -333,8 +339,12 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
rcu_read_lock(); l3proto = __nf_nat_l3proto_find(orig_tuple->src.l3num); + if (IS_ERR_OR_NULL(l3proto)) + goto out; l4proto = __nf_nat_l4proto_find(orig_tuple->src.l3num, orig_tuple->dst.protonum); + if (!l4proto) + goto out;
/* 1) If this srcip/proto/src-proto-part is currently mapped, * and that same mapping gives a unique tuple within the given @@ -509,8 +519,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 (IS_ERR_OR_NULL(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 +830,9 @@ 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 -EPROTONOSUPPORT; + if (l4proto->nlattr_to_range) err = l4proto->nlattr_to_range(tb, range);
@@ -876,6 +893,8 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct, l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct)); if (l3proto == NULL) return -EAGAIN; + if (IS_ERR(l3proto)) + return PTR_ERR(l3proto);
/* No NAT information has been passed, allocate the null-binding */ if (attr == NULL)