summaryrefslogtreecommitdiff
path: root/net/ipv4/netfilter/ip_conntrack_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/netfilter/ip_conntrack_netlink.c')
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c103
1 files changed, 67 insertions, 36 deletions
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index d2a4fec22862..91fe8f2e38ff 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -27,6 +27,7 @@
#include <linux/errno.h>
#include <linux/netlink.h>
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/netfilter.h>
@@ -59,11 +60,13 @@ ctnetlink_dump_tuples_proto(struct sk_buff *skb,
NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
+ /* If no protocol helper is found, this function will return the
+ * generic protocol helper, so proto won't *ever* be NULL */
proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
- if (likely(proto && proto->tuple_to_nfattr)) {
+ if (likely(proto->tuple_to_nfattr))
ret = proto->tuple_to_nfattr(skb, tuple);
- ip_conntrack_proto_put(proto);
- }
+
+ ip_conntrack_proto_put(proto);
return ret;
@@ -128,9 +131,11 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
struct nfattr *nest_proto;
int ret;
-
- if (!proto || !proto->to_nfattr)
+
+ if (!proto->to_nfattr) {
+ ip_conntrack_proto_put(proto);
return 0;
+ }
nest_proto = NFA_NEST(skb, CTA_PROTOINFO);
@@ -467,7 +472,7 @@ out:
}
#endif
-static const int cta_min_ip[CTA_IP_MAX] = {
+static const size_t cta_min_ip[CTA_IP_MAX] = {
[CTA_IP_V4_SRC-1] = sizeof(u_int32_t),
[CTA_IP_V4_DST-1] = sizeof(u_int32_t),
};
@@ -497,8 +502,8 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
return 0;
}
-static const int cta_min_proto[CTA_PROTO_MAX] = {
- [CTA_PROTO_NUM-1] = sizeof(u_int16_t),
+static const size_t cta_min_proto[CTA_PROTO_MAX] = {
+ [CTA_PROTO_NUM-1] = sizeof(u_int8_t),
[CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t),
[CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t),
[CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t),
@@ -523,14 +528,14 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr,
if (!tb[CTA_PROTO_NUM-1])
return -EINVAL;
- tuple->dst.protonum = *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
+ tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
- if (likely(proto && proto->nfattr_to_tuple)) {
+ if (likely(proto->nfattr_to_tuple))
ret = proto->nfattr_to_tuple(tb, tuple);
- ip_conntrack_proto_put(proto);
- }
+
+ ip_conntrack_proto_put(proto);
return ret;
}
@@ -576,7 +581,7 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
}
#ifdef CONFIG_IP_NF_NAT_NEEDED
-static const int cta_min_protonat[CTA_PROTONAT_MAX] = {
+static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = {
[CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t),
[CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t),
};
@@ -596,8 +601,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
return -EINVAL;
npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
- if (!npt)
- return 0;
if (!npt->nfattr_to_range) {
ip_nat_proto_put(npt);
@@ -614,6 +617,11 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
return 0;
}
+static const size_t cta_min_nat[CTA_NAT_MAX] = {
+ [CTA_NAT_MINIP-1] = sizeof(u_int32_t),
+ [CTA_NAT_MAXIP-1] = sizeof(u_int32_t),
+};
+
static inline int
ctnetlink_parse_nat(struct nfattr *cda[],
const struct ip_conntrack *ct, struct ip_nat_range *range)
@@ -627,6 +635,9 @@ ctnetlink_parse_nat(struct nfattr *cda[],
nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
+ if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
+ return -EINVAL;
+
if (tb[CTA_NAT_MINIP-1])
range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
@@ -667,6 +678,14 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
return 0;
}
+static const size_t cta_min[CTA_MAX] = {
+ [CTA_STATUS-1] = sizeof(u_int32_t),
+ [CTA_TIMEOUT-1] = sizeof(u_int32_t),
+ [CTA_MARK-1] = sizeof(u_int32_t),
+ [CTA_USE-1] = sizeof(u_int32_t),
+ [CTA_ID-1] = sizeof(u_int32_t)
+};
+
static int
ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
@@ -678,6 +697,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
DEBUGP("entered %s\n", __FUNCTION__);
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
if (cda[CTA_TUPLE_ORIG-1])
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
else if (cda[CTA_TUPLE_REPLY-1])
@@ -706,11 +728,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
return -ENOENT;
}
}
- if (del_timer(&ct->timeout)) {
- ip_conntrack_put(ct);
+ if (del_timer(&ct->timeout))
ct->timeout.function((unsigned long)ct);
- return 0;
- }
+
ip_conntrack_put(ct);
DEBUGP("leaving\n");
@@ -760,6 +780,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
return 0;
}
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
if (cda[CTA_TUPLE_ORIG-1])
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
else if (cda[CTA_TUPLE_REPLY-1])
@@ -852,7 +875,7 @@ ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
DEBUGP("NAT status: %lu\n",
status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
- if (ip_nat_initialized(ct, hooknum))
+ if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
return -EEXIST;
ip_nat_setup_info(ct, &range, hooknum);
@@ -935,8 +958,6 @@ ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[])
nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr);
proto = ip_conntrack_proto_find_get(npt);
- if (!proto)
- return -EINVAL;
if (proto->from_nfattr)
err = proto->from_nfattr(tb, ct);
@@ -1047,6 +1068,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
DEBUGP("entered %s\n", __FUNCTION__);
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
if (cda[CTA_TUPLE_ORIG-1]) {
err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG);
if (err < 0)
@@ -1252,6 +1276,11 @@ out:
return skb->len;
}
+static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
+ [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t),
+ [CTA_EXPECT_ID-1] = sizeof(u_int32_t)
+};
+
static int
ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
@@ -1263,6 +1292,9 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
DEBUGP("entered %s\n", __FUNCTION__);
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct nfgenmsg *msg = NLMSG_DATA(nlh);
u32 rlen;
@@ -1333,6 +1365,9 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
struct ip_conntrack_helper *h;
int err;
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
if (cda[CTA_EXPECT_TUPLE-1]) {
/* delete a single expect by tuple */
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
@@ -1462,6 +1497,9 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
DEBUGP("entered %s\n", __FUNCTION__);
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
if (!cda[CTA_EXPECT_TUPLE-1]
|| !cda[CTA_EXPECT_MASK-1]
|| !cda[CTA_EXPECT_MASTER-1])
@@ -1504,29 +1542,22 @@ static struct notifier_block ctnl_notifier_exp = {
static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
[IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
- .attr_count = CTA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_MAX, },
[IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
- .attr_count = CTA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_MAX, },
[IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
- .attr_count = CTA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_MAX, },
[IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
- .attr_count = CTA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_MAX, },
};
static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
[IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
- .attr_count = CTA_EXPECT_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_EXPECT_MAX, },
[IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
- .attr_count = CTA_EXPECT_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_EXPECT_MAX, },
[IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
- .attr_count = CTA_EXPECT_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_EXPECT_MAX, },
};
static struct nfnetlink_subsystem ctnl_subsys = {