From a0f65a267dd62aef4e003f833ea6290fd1e07b34 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 10 Mar 2012 12:15:15 +0100 Subject: netfilter: xt_LOG: use CONFIG_IP6_NF_IPTABLES instead of CONFIG_IPV6 This fixes the following linking error: xt_LOG.c:(.text+0x789b1): undefined reference to `ip6t_ext_hdr' ifdefs have to use CONFIG_IP6_NF_IPTABLES instead of CONFIG_IPV6. Acked-by: Randy Dunlap Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_LOG.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index f99f8dee238b..ff5f75fddb15 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -480,7 +480,7 @@ ipt_log_packet(u_int8_t pf, sb_close(m); } -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) /* One level of recursion won't kill us */ static void dump_ipv6_packet(struct sbuff *m, const struct nf_loginfo *info, @@ -824,7 +824,7 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par) if (par->family == NFPROTO_IPV4) ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, par->out, &li, loginfo->prefix); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) else if (par->family == NFPROTO_IPV6) ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, par->out, &li, loginfo->prefix); @@ -864,7 +864,7 @@ static struct xt_target log_tg_regs[] __read_mostly = { .checkentry = log_tg_check, .me = THIS_MODULE, }, -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) { .name = "LOG", .family = NFPROTO_IPV6, @@ -882,7 +882,7 @@ static struct nf_logger ipt_log_logger __read_mostly = { .me = THIS_MODULE, }; -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) static struct nf_logger ip6t_log_logger __read_mostly = { .name = "ip6t_LOG", .logfn = &ip6t_log_packet, @@ -899,7 +899,7 @@ static int __init log_tg_init(void) return ret; nf_log_register(NFPROTO_IPV4, &ipt_log_logger); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) nf_log_register(NFPROTO_IPV6, &ip6t_log_logger); #endif return 0; @@ -908,7 +908,7 @@ static int __init log_tg_init(void) static void __exit log_tg_exit(void) { nf_log_unregister(&ipt_log_logger); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) nf_log_unregister(&ip6t_log_logger); #endif xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); -- cgit v1.2.3 From c1ebd7dff700277e4d0a3da36833a406142e31d4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 22 Mar 2012 23:40:01 +0100 Subject: netfilter: cttimeout: fix dependency with l4protocol conntrack module This patch introduces nf_conntrack_l4proto_find_get() and nf_conntrack_l4proto_put() to fix module dependencies between timeout objects and l4-protocol conntrack modules. Thus, we make sure that the module cannot be removed if it is used by any of the cttimeout objects. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_l4proto.h | 4 +++ include/net/netfilter/nf_conntrack_timeout.h | 2 +- net/netfilter/nf_conntrack_proto.c | 21 +++++++++++++ net/netfilter/nfnetlink_cttimeout.c | 45 ++++++++++++++-------------- net/netfilter/xt_CT.c | 6 ++-- 5 files changed, 53 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 90c67c7db7e9..3b572bb20aa2 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -118,6 +118,10 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; extern struct nf_conntrack_l4proto * __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto); +extern struct nf_conntrack_l4proto * +nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto); +extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p); + /* Protocol registration. */ extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto); extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto); diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h index 0e04db4a0865..34ec89f8dbf9 100644 --- a/include/net/netfilter/nf_conntrack_timeout.h +++ b/include/net/netfilter/nf_conntrack_timeout.h @@ -15,7 +15,7 @@ struct ctnl_timeout { atomic_t refcnt; char name[CTNL_TIMEOUT_NAME_MAX]; __u16 l3num; - __u8 l4num; + struct nf_conntrack_l4proto *l4proto; char data[0]; }; diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 5701c8dd783c..be3da2c8cdc5 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -127,6 +127,27 @@ void nf_ct_l3proto_module_put(unsigned short l3proto) } EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); +struct nf_conntrack_l4proto * +nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num) +{ + struct nf_conntrack_l4proto *p; + + rcu_read_lock(); + p = __nf_ct_l4proto_find(l3num, l4num); + if (!try_module_get(p->me)) + p = &nf_conntrack_l4proto_generic; + rcu_read_unlock(); + + return p; +} +EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); + +void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) +{ + module_put(p->me); +} +EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); + static int kill_l3proto(struct nf_conn *i, void *data) { return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto; diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index fec29a43de4d..2b9e79f5ef05 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -98,11 +98,13 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, break; } - l4proto = __nf_ct_l4proto_find(l3num, l4num); + l4proto = nf_ct_l4proto_find_get(l3num, l4num); /* This protocol is not supportted, skip. */ - if (l4proto->l4proto != l4num) - return -EOPNOTSUPP; + if (l4proto->l4proto != l4num) { + ret = -EOPNOTSUPP; + goto err_proto_put; + } if (matching) { if (nlh->nlmsg_flags & NLM_F_REPLACE) { @@ -110,20 +112,25 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, * different kind, sorry. */ if (matching->l3num != l3num || - matching->l4num != l4num) - return -EINVAL; + matching->l4proto->l4proto != l4num) { + ret = -EINVAL; + goto err_proto_put; + } ret = ctnl_timeout_parse_policy(matching, l4proto, cda[CTA_TIMEOUT_DATA]); return ret; } - return -EBUSY; + ret = -EBUSY; + goto err_proto_put; } timeout = kzalloc(sizeof(struct ctnl_timeout) + l4proto->ctnl_timeout.obj_size, GFP_KERNEL); - if (timeout == NULL) - return -ENOMEM; + if (timeout == NULL) { + ret = -ENOMEM; + goto err_proto_put; + } ret = ctnl_timeout_parse_policy(timeout, l4proto, cda[CTA_TIMEOUT_DATA]); @@ -132,13 +139,15 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); timeout->l3num = l3num; - timeout->l4num = l4num; + timeout->l4proto = l4proto; atomic_set(&timeout->refcnt, 1); list_add_tail_rcu(&timeout->head, &cttimeout_list); return 0; err: kfree(timeout); +err_proto_put: + nf_ct_l4proto_put(l4proto); return ret; } @@ -149,7 +158,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; unsigned int flags = pid ? NLM_F_MULTI : 0; - struct nf_conntrack_l4proto *l4proto; + struct nf_conntrack_l4proto *l4proto = timeout->l4proto; event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); @@ -163,20 +172,10 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name); NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)); - NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num); + NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto); NLA_PUT_BE32(skb, CTA_TIMEOUT_USE, htonl(atomic_read(&timeout->refcnt))); - l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num); - - /* If the timeout object does not match the layer 4 protocol tracker, - * then skip dumping the data part since we don't know how to - * interpret it. This may happen for UPDlite, SCTP and DCCP since - * you can unload the module. - */ - if (timeout->l4num != l4proto->l4proto) - goto out; - if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { struct nlattr *nest_parms; int ret; @@ -192,7 +191,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, nla_nest_end(skb, nest_parms); } -out: + nlmsg_end(skb, nlh); return skb->len; @@ -293,6 +292,7 @@ static int ctnl_timeout_try_del(struct ctnl_timeout *timeout) if (atomic_dec_and_test(&timeout->refcnt)) { /* We are protected by nfnl mutex. */ list_del_rcu(&timeout->head); + nf_ct_l4proto_put(timeout->l4proto); kfree_rcu(timeout, rcu_head); } else { /* still in use, restore reference counter. */ @@ -417,6 +417,7 @@ static void __exit cttimeout_exit(void) /* We are sure that our objects have no clients at this point, * it's safe to release them all without checking refcnt. */ + nf_ct_l4proto_put(cur->l4proto); kfree_rcu(cur, rcu_head); } #ifdef CONFIG_NF_CONNTRACK_TIMEOUT diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index b873445df444..80c39f0f6e91 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -243,11 +244,12 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) info->timeout, timeout->l3num); goto err3; } - if (timeout->l4num != e->ip.proto) { + if (timeout->l4proto->l4proto != e->ip.proto) { ret = -EINVAL; pr_info("Timeout policy `%s' can only be " "used by L4 protocol number %d\n", - info->timeout, timeout->l4num); + info->timeout, + timeout->l4proto->l4proto); goto err3; } timeout_ext = nf_ct_timeout_ext_add(ct, timeout, -- cgit v1.2.3 From 1ac0bf99260761ad0a536ddbc15f6f9b82b9bab3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 22 Mar 2012 23:58:41 +0100 Subject: netfilter: xt_CT: missing rcu_read_lock section in timeout assignment Fix a dereference to pointer without rcu_read_lock held. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_CT.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 80c39f0f6e91..33a02b41abb4 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -218,6 +218,7 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) struct ctnl_timeout *timeout; struct nf_conn_timeout *timeout_ext; + rcu_read_lock(); timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook); @@ -228,21 +229,21 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) ret = -EINVAL; pr_info("You cannot use inversion on " "L4 protocol\n"); - goto err3; + goto err4; } timeout = timeout_find_get(info->timeout); if (timeout == NULL) { ret = -ENOENT; pr_info("No such timeout policy \"%s\"\n", info->timeout); - goto err3; + goto err4; } if (timeout->l3num != par->family) { ret = -EINVAL; pr_info("Timeout policy `%s' can only be " "used by L3 protocol number %d\n", info->timeout, timeout->l3num); - goto err3; + goto err4; } if (timeout->l4proto->l4proto != e->ip.proto) { ret = -EINVAL; @@ -250,19 +251,20 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) "used by L4 protocol number %d\n", info->timeout, timeout->l4proto->l4proto); - goto err3; + goto err4; } timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_KERNEL); if (timeout_ext == NULL) { ret = -ENOMEM; - goto err3; + goto err4; } } else { ret = -ENOENT; pr_info("Timeout policy base is empty\n"); - goto err3; + goto err4; } + rcu_read_unlock(); } #endif @@ -272,6 +274,8 @@ out: info->ct = ct; return 0; +err4: + rcu_read_unlock(); err3: nf_conntrack_free(ct); err2: @@ -313,6 +317,7 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) nf_ct_l3proto_module_put(par->family); #ifdef CONFIG_NF_CONNTRACK_TIMEOUT + rcu_read_lock(); timeout_put = rcu_dereference(nf_ct_timeout_put_hook); if (timeout_put) { @@ -320,6 +325,7 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) if (timeout_ext) timeout_put(timeout_ext->timeout); } + rcu_read_unlock(); #endif } nf_ct_put(info->ct); -- cgit v1.2.3 From eeb4cb952386aac764a5cf4cf2490e50a24a8880 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 23 Mar 2012 00:02:07 +0100 Subject: netfilter: xt_CT: fix assignation of the generic protocol tracker `iptables -p all' uses 0 to match all protocols, while the conntrack subsystem uses 255. We still need `-p all' to attach the custom timeout policies for the generic protocol tracker. Moreover, we may use `iptables -p sctp' while the SCTP tracker is not loaded. In that case, we have to default on the generic protocol tracker. Another possibility is `iptables -p ip' that should be supported as well. This patch makes sure we validate all possible scenarios. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_CT.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 33a02b41abb4..0c8e43810ce3 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,7 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) if (timeout_find_get) { const struct ipt_entry *e = par->entryinfo; + struct nf_conntrack_l4proto *l4proto; if (e->ip.invflags & IPT_INV_PROTO) { ret = -EINVAL; @@ -245,7 +247,12 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) info->timeout, timeout->l3num); goto err4; } - if (timeout->l4proto->l4proto != e->ip.proto) { + /* Make sure the timeout policy matches any existing + * protocol tracker, otherwise default to generic. + */ + l4proto = __nf_ct_l4proto_find(par->family, + e->ip.proto); + if (timeout->l4proto->l4proto != l4proto->l4proto) { ret = -EINVAL; pr_info("Timeout policy `%s' can only be " "used by L4 protocol number %d\n", -- cgit v1.2.3 From 60b5f8f745739a4789395648595ed31ede582448 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 23 Mar 2012 00:04:53 +0100 Subject: netfilter: nf_conntrack: permanently attach timeout policy to conntrack We need to permanently attach the timeout policy to the conntrack, otherwise we may apply the custom timeout policy inconsistently. Without this patch, the following example: nfct timeout add test inet icmp timeout 100 iptables -I PREROUTING -t raw -p icmp -s 1.1.1.1 -j CT --timeout test Will only apply the custom timeout policy to outgoing packets from 1.1.1.1, but not to reply packets from 2.2.2.2 going to 1.1.1.1. To fix this issue, this patch modifies the current logic to attach the timeout policy when the first packet is seen (which is when the conntrack entry is created). Then, we keep using the attached timeout policy until the conntrack entry is destroyed. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_core.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 7b48035826ee..cbdb754dbb10 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -768,8 +768,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, struct sk_buff *skb, - unsigned int dataoff, u32 hash, - unsigned int *timeouts) + unsigned int dataoff, u32 hash) { struct nf_conn *ct; struct nf_conn_help *help; @@ -777,6 +776,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_ecache *ecache; struct nf_conntrack_expect *exp; u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; + struct nf_conn_timeout *timeout_ext; + unsigned int *timeouts; if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { pr_debug("Can't invert tuple.\n"); @@ -788,12 +789,21 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, if (IS_ERR(ct)) return (struct nf_conntrack_tuple_hash *)ct; + timeout_ext = tmpl ? nf_ct_timeout_find(tmpl) : NULL; + if (timeout_ext) + timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); + else + timeouts = l4proto->get_timeouts(net); + if (!l4proto->new(ct, skb, dataoff, timeouts)) { nf_conntrack_free(ct); pr_debug("init conntrack: can't track with proto module\n"); return NULL; } + if (timeout_ext) + nf_ct_timeout_ext_add(ct, timeout_ext->timeout, GFP_ATOMIC); + nf_ct_acct_ext_add(ct, GFP_ATOMIC); nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); @@ -854,8 +864,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, int *set_reply, - enum ip_conntrack_info *ctinfo, - unsigned int *timeouts) + enum ip_conntrack_info *ctinfo) { struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple_hash *h; @@ -875,7 +884,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, h = __nf_conntrack_find_get(net, zone, &tuple, hash); if (!h) { h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, - skb, dataoff, hash, timeouts); + skb, dataoff, hash); if (!h) return NULL; if (IS_ERR(h)) @@ -964,19 +973,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, goto out; } - /* Decide what timeout policy we want to apply to this flow. */ - if (tmpl) { - timeout_ext = nf_ct_timeout_find(tmpl); - if (timeout_ext) - timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); - else - timeouts = l4proto->get_timeouts(net); - } else - timeouts = l4proto->get_timeouts(net); - ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, - l3proto, l4proto, &set_reply, &ctinfo, - timeouts); + l3proto, l4proto, &set_reply, &ctinfo); if (!ct) { /* Not valid part of a connection */ NF_CT_STAT_INC_ATOMIC(net, invalid); @@ -993,6 +991,13 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, NF_CT_ASSERT(skb->nfct); + /* Decide what timeout policy we want to apply to this flow. */ + timeout_ext = nf_ct_timeout_find(ct); + if (timeout_ext) + timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); + else + timeouts = l4proto->get_timeouts(net); + ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts); if (ret <= 0) { /* Invalid: inverse of the return code tells -- cgit v1.2.3