Skip to content

Commit

Permalink
Merge branch 'master' of git://1984.lsi.us.es/nf-next
Browse files Browse the repository at this point in the history
Pablo says:

====================
The following patchset provides fixes for issues that were recently introduced
by my new cthelper infrastructure. They have been spotted by Randy Dunlap,
Andrew Morton and Dan Carpenter.

The patches provide:

* compilation fixes if CONFIG_NF_CONNTRACK is disabled: I moved all the
  conntrack code from nfnetlink_queue.c to nfnetlink_queue_ct.c to avoid
  peppering the entire code with lots of ifdefs. I needed to rename
  nfnetlink_queue.c to nfnetlink_queue_core.c to get it working with the
  Makefile tweaks I've added.

* fix NULL pointer dereference via ctnetlink while trying to change the helper
  for an existing conntrack entry. I don't find any reasonable use case for
  changing the helper from one to another in run-time. Thus, now ctnetlink
  returns -EOPNOTSUPP for this operation.

* fix possible out-of-bound zeroing of the conntrack extension area due to
  the helper automatic assignation routine.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 19, 2012
2 parents f032537 + 7c62234 commit 6bdc5f4
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 67 deletions.
43 changes: 43 additions & 0 deletions include/net/netfilter/nfnetlink_queue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef _NET_NFNL_QUEUE_H_
#define _NET_NFNL_QUEUE_H_

#include <linux/netfilter/nf_conntrack_common.h>

struct nf_conn;

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct nf_conn *nfqnl_ct_get(struct sk_buff *entskb, size_t *size,
enum ip_conntrack_info *ctinfo);
struct nf_conn *nfqnl_ct_parse(const struct sk_buff *skb,
const struct nlattr *attr,
enum ip_conntrack_info *ctinfo);
int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo);
void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, int diff);
#else
inline struct nf_conn *
nfqnl_ct_get(struct sk_buff *entskb, size_t *size, enum ip_conntrack_info *ctinfo)
{
return NULL;
}

inline struct nf_conn *nfqnl_ct_parse(const struct sk_buff *skb,
const struct nlattr *attr,
enum ip_conntrack_info *ctinfo)
{
return NULL;
}

inline int
nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
return 0;
}

inline void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, int diff)
{
}
#endif /* NF_CONNTRACK */
#endif
29 changes: 21 additions & 8 deletions net/netfilter/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ tristate "Netfilter NFACCT over NFNETLINK interface"
If this option is enabled, the kernel will include support
for extended accounting via NFNETLINK.

config NETFILTER_NETLINK_CTHELPER
tristate "Netfilter CTHELPER over NFNETLINK interface"
depends on NETFILTER_ADVANCED
select NETFILTER_NETLINK
help
If this option is enabled, the kernel will include support
for user-space connection tracking helpers via NFNETLINK.

config NETFILTER_NETLINK_QUEUE
tristate "Netfilter NFQUEUE over NFNETLINK interface"
depends on NETFILTER_ADVANCED
Expand Down Expand Up @@ -343,6 +335,27 @@ config NF_CT_NETLINK_TIMEOUT

If unsure, say `N'.

config NF_CT_NETLINK_HELPER
tristate 'Connection tracking helpers in user-space via Netlink'
select NETFILTER_NETLINK
depends on NF_CT_NETLINK
depends on NETFILTER_NETLINK_QUEUE
depends on NETFILTER_NETLINK_QUEUE_CT
depends on NETFILTER_ADVANCED
help
This option enables the user-space connection tracking helpers
infrastructure.

If unsure, say `N'.

config NETFILTER_NETLINK_QUEUE_CT
bool "NFQUEUE integration with Connection Tracking"
default n
depends on NETFILTER_NETLINK_QUEUE
help
If this option is enabled, NFQUEUE can include Connection Tracking
information together with the packet is the enqueued via NFNETLINK.

endif # NF_CONNTRACK

# transparent proxy support
Expand Down
4 changes: 3 additions & 1 deletion net/netfilter/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ obj-$(CONFIG_NETFILTER) = netfilter.o

obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
obj-$(CONFIG_NETFILTER_NETLINK_ACCT) += nfnetlink_acct.o
obj-$(CONFIG_NETFILTER_NETLINK_CTHELPER) += nfnetlink_cthelper.o
nfnetlink_queue-y := nfnetlink_queue_core.o
nfnetlink_queue-$(CONFIG_NETFILTER_NETLINK_QUEUE_CT) += nfnetlink_queue_ct.o
obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o

Expand All @@ -25,6 +26,7 @@ obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o
# netlink interface for nf_conntrack
obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
obj-$(CONFIG_NF_CT_NETLINK_TIMEOUT) += nfnetlink_cttimeout.o
obj-$(CONFIG_NF_CT_NETLINK_HELPER) += nfnetlink_cthelper.o

# connection tracking helpers
nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o
Expand Down
8 changes: 7 additions & 1 deletion net/netfilter/nf_conntrack_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,13 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
goto out;
}
} else {
memset(help->data, 0, helper->data_len);
/* We only allow helper re-assignment of the same sort since
* we cannot reallocate the helper extension area.
*/
if (help->helper != helper) {
RCU_INIT_POINTER(help->helper, NULL);
goto out;
}
}

rcu_assign_pointer(help->helper, helper);
Expand Down
24 changes: 7 additions & 17 deletions net/netfilter/nf_conntrack_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1224,19 +1224,12 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
if (helper->from_nlattr && helpinfo)
helper->from_nlattr(helpinfo, ct);
return 0;
}
if (help->helper)
} else
return -EBUSY;
/* need to zero data of old helper */
memset(help->data, 0, help->helper->data_len);
} else {
/* we cannot set a helper for an existing conntrack */
return -EOPNOTSUPP;
}

rcu_assign_pointer(help->helper, helper);

return 0;
/* we cannot set a helper for an existing conntrack */
return -EOPNOTSUPP;
}

static inline int
Expand Down Expand Up @@ -1634,8 +1627,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err;
}

#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || \
defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
static size_t
ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
{
Expand Down Expand Up @@ -1769,7 +1761,7 @@ static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
.seq_adjust = nf_nat_tcp_seq_adjust,
#endif
};
#endif /* CONFIG_NETFILTER_NETLINK_QUEUE */
#endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */

/***********************************************************************
* EXPECT
Expand Down Expand Up @@ -2575,8 +2567,7 @@ static int __init ctnetlink_init(void)
pr_err("ctnetlink_init: cannot register pernet operations\n");
goto err_unreg_exp_subsys;
}
#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || \
defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
/* setup interaction between nf_queue and nf_conntrack_netlink. */
RCU_INIT_POINTER(nfq_ct_hook, &ctnetlink_nfqueue_hook);
#endif
Expand All @@ -2597,8 +2588,7 @@ static void __exit ctnetlink_exit(void)
unregister_pernet_subsys(&ctnetlink_net_ops);
nfnetlink_subsys_unregister(&ctnl_exp_subsys);
nfnetlink_subsys_unregister(&ctnl_subsys);
#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || \
defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
RCU_INIT_POINTER(nfq_ct_hook, NULL);
#endif
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#include <linux/list.h>
#include <net/sock.h>
#include <net/netfilter/nf_queue.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nfnetlink_queue.h>

#include <linux/atomic.h>

Expand Down Expand Up @@ -234,7 +234,6 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
struct sk_buff *entskb = entry->skb;
struct net_device *indev;
struct net_device *outdev;
struct nfq_ct_hook *nfq_ct;
struct nf_conn *ct = NULL;
enum ip_conntrack_info uninitialized_var(ctinfo);

Expand Down Expand Up @@ -270,17 +269,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
break;
}

/* rcu_read_lock()ed by __nf_queue already. */
nfq_ct = rcu_dereference(nfq_ct_hook);
if (nfq_ct != NULL && (queue->flags & NFQA_CFG_F_CONNTRACK)) {
ct = nf_ct_get(entskb, &ctinfo);
if (ct) {
if (!nf_ct_is_untracked(ct))
size += nfq_ct->build_size(ct);
else
ct = NULL;
}
}
if (queue->flags & NFQA_CFG_F_CONNTRACK)
ct = nfqnl_ct_get(entskb, &size, &ctinfo);

skb = alloc_skb(size, GFP_ATOMIC);
if (!skb)
Expand Down Expand Up @@ -404,23 +394,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
BUG();
}

if (ct) {
struct nlattr *nest_parms;
u_int32_t tmp;

nest_parms = nla_nest_start(skb, NFQA_CT | NLA_F_NESTED);
if (!nest_parms)
goto nla_put_failure;

if (nfq_ct->build(skb, ct) < 0)
goto nla_put_failure;

nla_nest_end(skb, nest_parms);

tmp = ctinfo;
if (nla_put_u32(skb, NFQA_CT_INFO, htonl(ctinfo)))
goto nla_put_failure;
}
if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0)
goto nla_put_failure;

nlh->nlmsg_len = skb->tail - old_tail;
return skb;
Expand Down Expand Up @@ -764,7 +739,6 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
struct nfqnl_instance *queue;
unsigned int verdict;
struct nf_queue_entry *entry;
struct nfq_ct_hook *nfq_ct;
enum ip_conntrack_info uninitialized_var(ctinfo);
struct nf_conn *ct = NULL;

Expand All @@ -786,13 +760,8 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
return -ENOENT;

rcu_read_lock();
nfq_ct = rcu_dereference(nfq_ct_hook);
if (nfq_ct != NULL &&
(queue->flags & NFQA_CFG_F_CONNTRACK) && nfqa[NFQA_CT]) {
ct = nf_ct_get(entry->skb, &ctinfo);
if (ct && !nf_ct_is_untracked(ct))
nfq_ct->parse(nfqa[NFQA_CT], ct);
}
if (nfqa[NFQA_CT] && (queue->flags & NFQA_CFG_F_CONNTRACK))
ct = nfqnl_ct_parse(entry->skb, nfqa[NFQA_CT], &ctinfo);

if (nfqa[NFQA_PAYLOAD]) {
u16 payload_len = nla_len(nfqa[NFQA_PAYLOAD]);
Expand All @@ -802,8 +771,8 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
payload_len, entry, diff) < 0)
verdict = NF_DROP;

if (ct && (ct->status & IPS_NAT_MASK) && diff)
nfq_ct->seq_adjust(skb, ct, ctinfo, diff);
if (ct)
nfqnl_ct_seq_adjust(skb, ct, ctinfo, diff);
}
rcu_read_unlock();

Expand Down
97 changes: 97 additions & 0 deletions net/netfilter/nfnetlink_queue_ct.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/

#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_queue.h>
#include <net/netfilter/nf_conntrack.h>

struct nf_conn *nfqnl_ct_get(struct sk_buff *entskb, size_t *size,
enum ip_conntrack_info *ctinfo)
{
struct nfq_ct_hook *nfq_ct;
struct nf_conn *ct;

/* rcu_read_lock()ed by __nf_queue already. */
nfq_ct = rcu_dereference(nfq_ct_hook);
if (nfq_ct == NULL)
return NULL;

ct = nf_ct_get(entskb, ctinfo);
if (ct) {
if (!nf_ct_is_untracked(ct))
*size += nfq_ct->build_size(ct);
else
ct = NULL;
}
return ct;
}

struct nf_conn *
nfqnl_ct_parse(const struct sk_buff *skb, const struct nlattr *attr,
enum ip_conntrack_info *ctinfo)
{
struct nfq_ct_hook *nfq_ct;
struct nf_conn *ct;

/* rcu_read_lock()ed by __nf_queue already. */
nfq_ct = rcu_dereference(nfq_ct_hook);
if (nfq_ct == NULL)
return NULL;

ct = nf_ct_get(skb, ctinfo);
if (ct && !nf_ct_is_untracked(ct))
nfq_ct->parse(attr, ct);

return ct;
}

int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
struct nfq_ct_hook *nfq_ct;
struct nlattr *nest_parms;
u_int32_t tmp;

nfq_ct = rcu_dereference(nfq_ct_hook);
if (nfq_ct == NULL)
return 0;

nest_parms = nla_nest_start(skb, NFQA_CT | NLA_F_NESTED);
if (!nest_parms)
goto nla_put_failure;

if (nfq_ct->build(skb, ct) < 0)
goto nla_put_failure;

nla_nest_end(skb, nest_parms);

tmp = ctinfo;
if (nla_put_be32(skb, NFQA_CT_INFO, htonl(tmp)))
goto nla_put_failure;

return 0;

nla_put_failure:
return -1;
}

void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo, int diff)
{
struct nfq_ct_hook *nfq_ct;

nfq_ct = rcu_dereference(nfq_ct_hook);
if (nfq_ct == NULL)
return;

if ((ct->status & IPS_NAT_MASK) && diff)
nfq_ct->seq_adjust(skb, ct, ctinfo, diff);
}

0 comments on commit 6bdc5f4

Please sign in to comment.