diff options
Diffstat (limited to 'net/netfilter/nfnetlink_log.c')
| -rw-r--r-- | net/netfilter/nfnetlink_log.c | 413 | 
1 files changed, 253 insertions, 160 deletions
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 6a1572b0ab4..d292c8d286e 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -3,6 +3,7 @@   * nfetlink.   *   * (C) 2005 by Harald Welte <laforge@netfilter.org> + * (C) 2006-2012 Patrick McHardy <kaber@trash.net>   *   * Based on the old ipv4-only ipt_ULOG.c:   * (C) 2000-2004 by Harald Welte <laforge@netfilter.org> @@ -13,12 +14,13 @@   */  #include <linux/module.h>  #include <linux/skbuff.h> +#include <linux/if_arp.h>  #include <linux/init.h>  #include <linux/ip.h>  #include <linux/ipv6.h>  #include <linux/netdevice.h>  #include <linux/netfilter.h> -#include <linux/netlink.h> +#include <net/netlink.h>  #include <linux/netfilter/nfnetlink.h>  #include <linux/netfilter/nfnetlink_log.h>  #include <linux/spinlock.h> @@ -26,14 +28,13 @@  #include <linux/proc_fs.h>  #include <linux/security.h>  #include <linux/list.h> -#include <linux/jhash.h> -#include <linux/random.h>  #include <linux/slab.h>  #include <net/sock.h>  #include <net/netfilter/nf_log.h> +#include <net/netns/generic.h>  #include <net/netfilter/nfnetlink_log.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #ifdef CONFIG_BRIDGE_NETFILTER  #include "../bridge/br_private.h" @@ -55,7 +56,9 @@ struct nfulnl_instance {  	unsigned int qlen;		/* number of nlmsgs in skb */  	struct sk_buff *skb;		/* pre-allocatd skb */  	struct timer_list timer; -	int peer_pid;			/* PID of the peer process */ +	struct net *net; +	struct user_namespace *peer_user_ns;	/* User namespace of the peer process */ +	int peer_portid;			/* PORTID of the peer process */  	/* configurable parameters */  	unsigned int flushtimeout;	/* timeout until queue flush */ @@ -69,12 +72,20 @@ struct nfulnl_instance {  	struct rcu_head rcu;  }; -static DEFINE_SPINLOCK(instances_lock); -static atomic_t global_seq; -  #define INSTANCE_BUCKETS	16 -static struct hlist_head instance_table[INSTANCE_BUCKETS]; -static unsigned int hash_init; + +static int nfnl_log_net_id __read_mostly; + +struct nfnl_log_net { +	spinlock_t instances_lock; +	struct hlist_head instance_table[INSTANCE_BUCKETS]; +	atomic_t global_seq; +}; + +static struct nfnl_log_net *nfnl_log_pernet(struct net *net) +{ +	return net_generic(net, nfnl_log_net_id); +}  static inline u_int8_t instance_hashfn(u_int16_t group_num)  { @@ -82,14 +93,13 @@ static inline u_int8_t instance_hashfn(u_int16_t group_num)  }  static struct nfulnl_instance * -__instance_lookup(u_int16_t group_num) +__instance_lookup(struct nfnl_log_net *log, u_int16_t group_num)  {  	struct hlist_head *head; -	struct hlist_node *pos;  	struct nfulnl_instance *inst; -	head = &instance_table[instance_hashfn(group_num)]; -	hlist_for_each_entry_rcu(inst, pos, head, hlist) { +	head = &log->instance_table[instance_hashfn(group_num)]; +	hlist_for_each_entry_rcu(inst, head, hlist) {  		if (inst->group_num == group_num)  			return inst;  	} @@ -103,12 +113,12 @@ instance_get(struct nfulnl_instance *inst)  }  static struct nfulnl_instance * -instance_lookup_get(u_int16_t group_num) +instance_lookup_get(struct nfnl_log_net *log, u_int16_t group_num)  {  	struct nfulnl_instance *inst;  	rcu_read_lock_bh(); -	inst = __instance_lookup(group_num); +	inst = __instance_lookup(log, group_num);  	if (inst && !atomic_inc_not_zero(&inst->use))  		inst = NULL;  	rcu_read_unlock_bh(); @@ -118,7 +128,11 @@ instance_lookup_get(u_int16_t group_num)  static void nfulnl_instance_free_rcu(struct rcu_head *head)  { -	kfree(container_of(head, struct nfulnl_instance, rcu)); +	struct nfulnl_instance *inst = +		container_of(head, struct nfulnl_instance, rcu); + +	put_net(inst->net); +	kfree(inst);  	module_put(THIS_MODULE);  } @@ -132,13 +146,15 @@ instance_put(struct nfulnl_instance *inst)  static void nfulnl_timer(unsigned long data);  static struct nfulnl_instance * -instance_create(u_int16_t group_num, int pid) +instance_create(struct net *net, u_int16_t group_num, +		int portid, struct user_namespace *user_ns)  {  	struct nfulnl_instance *inst; +	struct nfnl_log_net *log = nfnl_log_pernet(net);  	int err; -	spin_lock_bh(&instances_lock); -	if (__instance_lookup(group_num)) { +	spin_lock_bh(&log->instances_lock); +	if (__instance_lookup(log, group_num)) {  		err = -EEXIST;  		goto out_unlock;  	} @@ -162,7 +178,9 @@ instance_create(u_int16_t group_num, int pid)  	setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst); -	inst->peer_pid = pid; +	inst->net = get_net(net); +	inst->peer_user_ns = user_ns; +	inst->peer_portid = portid;  	inst->group_num = group_num;  	inst->qthreshold 	= NFULNL_QTHRESH_DEFAULT; @@ -172,14 +190,15 @@ instance_create(u_int16_t group_num, int pid)  	inst->copy_range 	= NFULNL_COPY_RANGE_MAX;  	hlist_add_head_rcu(&inst->hlist, -		       &instance_table[instance_hashfn(group_num)]); +		       &log->instance_table[instance_hashfn(group_num)]); + -	spin_unlock_bh(&instances_lock); +	spin_unlock_bh(&log->instances_lock);  	return inst;  out_unlock: -	spin_unlock_bh(&instances_lock); +	spin_unlock_bh(&log->instances_lock);  	return ERR_PTR(err);  } @@ -208,11 +227,12 @@ __instance_destroy(struct nfulnl_instance *inst)  }  static inline void -instance_destroy(struct nfulnl_instance *inst) +instance_destroy(struct nfnl_log_net *log, +		 struct nfulnl_instance *inst)  { -	spin_lock_bh(&instances_lock); +	spin_lock_bh(&log->instances_lock);  	__instance_destroy(inst); -	spin_unlock_bh(&instances_lock); +	spin_unlock_bh(&log->instances_lock);  }  static int @@ -296,7 +316,8 @@ nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags)  }  static struct sk_buff * -nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size) +nfulnl_alloc_skb(struct net *net, u32 peer_portid, unsigned int inst_size, +		 unsigned int pkt_size)  {  	struct sk_buff *skb;  	unsigned int n; @@ -305,19 +326,17 @@ nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size)  	 * message.  WARNING: has to be <= 128k due to slab restrictions */  	n = max(inst_size, pkt_size); -	skb = alloc_skb(n, GFP_ATOMIC); +	skb = nfnetlink_alloc_skb(net, n, peer_portid, GFP_ATOMIC);  	if (!skb) { -		pr_notice("nfnetlink_log: can't alloc whole buffer (%u bytes)\n", -			inst_size); -  		if (n > pkt_size) {  			/* try to allocate only as much as we need for current  			 * packet */ -			skb = alloc_skb(pkt_size, GFP_ATOMIC); +			skb = nfnetlink_alloc_skb(net, pkt_size, +						  peer_portid, GFP_ATOMIC);  			if (!skb) -				pr_err("nfnetlink_log: can't even alloc %u " -				       "bytes\n", pkt_size); +				pr_err("nfnetlink_log: can't even alloc %u bytes\n", +				       pkt_size);  		}  	} @@ -329,18 +348,20 @@ __nfulnl_send(struct nfulnl_instance *inst)  {  	int status = -1; -	if (inst->qlen > 1) -		NLMSG_PUT(inst->skb, 0, 0, -			  NLMSG_DONE, -			  sizeof(struct nfgenmsg)); - -	status = nfnetlink_unicast(inst->skb, &init_net, inst->peer_pid, +	if (inst->qlen > 1) { +		struct nlmsghdr *nlh = nlmsg_put(inst->skb, 0, 0, +						 NLMSG_DONE, +						 sizeof(struct nfgenmsg), +						 0); +		if (!nlh) +			goto out; +	} +	status = nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid,  				   MSG_DONTWAIT);  	inst->qlen = 0;  	inst->skb = NULL; - -nlmsg_failure: +out:  	return status;  } @@ -369,111 +390,139 @@ nfulnl_timer(unsigned long data)  /* This is an inline function, we don't really care about a long   * list of arguments */  static inline int -__build_packet_message(struct nfulnl_instance *inst, +__build_packet_message(struct nfnl_log_net *log, +			struct nfulnl_instance *inst,  			const struct sk_buff *skb,  			unsigned int data_len,  			u_int8_t pf,  			unsigned int hooknum,  			const struct net_device *indev,  			const struct net_device *outdev, -			const struct nf_loginfo *li,  			const char *prefix, unsigned int plen)  {  	struct nfulnl_msg_packet_hdr pmsg;  	struct nlmsghdr *nlh;  	struct nfgenmsg *nfmsg; -	__be32 tmp_uint;  	sk_buff_data_t old_tail = inst->skb->tail; +	struct sock *sk; +	const unsigned char *hwhdrp; -	nlh = NLMSG_PUT(inst->skb, 0, 0, +	nlh = nlmsg_put(inst->skb, 0, 0,  			NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET, -			sizeof(struct nfgenmsg)); -	nfmsg = NLMSG_DATA(nlh); +			sizeof(struct nfgenmsg), 0); +	if (!nlh) +		return -1; +	nfmsg = nlmsg_data(nlh);  	nfmsg->nfgen_family = pf;  	nfmsg->version = NFNETLINK_V0;  	nfmsg->res_id = htons(inst->group_num); +	memset(&pmsg, 0, sizeof(pmsg));  	pmsg.hw_protocol	= skb->protocol;  	pmsg.hook		= hooknum; -	NLA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg); +	if (nla_put(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg)) +		goto nla_put_failure; -	if (prefix) -		NLA_PUT(inst->skb, NFULA_PREFIX, plen, prefix); +	if (prefix && +	    nla_put(inst->skb, NFULA_PREFIX, plen, prefix)) +		goto nla_put_failure;  	if (indev) {  #ifndef CONFIG_BRIDGE_NETFILTER -		NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV, -			     htonl(indev->ifindex)); +		if (nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, +				 htonl(indev->ifindex))) +			goto nla_put_failure;  #else  		if (pf == PF_BRIDGE) {  			/* Case 1: outdev is physical input device, we need to  			 * look for bridge group (when called from  			 * netfilter_bridge) */ -			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV, -				     htonl(indev->ifindex)); +			if (nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV, +					 htonl(indev->ifindex)) ||  			/* this is the bridge group "brX" */  			/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */ -			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV, -				     htonl(br_port_get_rcu(indev)->br->dev->ifindex)); +			    nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, +					 htonl(br_port_get_rcu(indev)->br->dev->ifindex))) +				goto nla_put_failure;  		} else {  			/* Case 2: indev is bridge group, we need to look for  			 * physical device (when called from ipv4) */ -			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV, -				     htonl(indev->ifindex)); -			if (skb->nf_bridge && skb->nf_bridge->physindev) -				NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV, -					     htonl(skb->nf_bridge->physindev->ifindex)); +			if (nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, +					 htonl(indev->ifindex))) +				goto nla_put_failure; +			if (skb->nf_bridge && skb->nf_bridge->physindev && +			    nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV, +					 htonl(skb->nf_bridge->physindev->ifindex))) +				goto nla_put_failure;  		}  #endif  	}  	if (outdev) { -		tmp_uint = htonl(outdev->ifindex);  #ifndef CONFIG_BRIDGE_NETFILTER -		NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV, -			     htonl(outdev->ifindex)); +		if (nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, +				 htonl(outdev->ifindex))) +			goto nla_put_failure;  #else  		if (pf == PF_BRIDGE) {  			/* Case 1: outdev is physical output device, we need to  			 * look for bridge group (when called from  			 * netfilter_bridge) */ -			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, -				     htonl(outdev->ifindex)); +			if (nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, +					 htonl(outdev->ifindex)) ||  			/* this is the bridge group "brX" */  			/* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */ -			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV, -				     htonl(br_port_get_rcu(outdev)->br->dev->ifindex)); +			    nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, +					 htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) +				goto nla_put_failure;  		} else {  			/* Case 2: indev is a bridge group, we need to look  			 * for physical device (when called from ipv4) */ -			NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV, -				     htonl(outdev->ifindex)); -			if (skb->nf_bridge && skb->nf_bridge->physoutdev) -				NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, -					     htonl(skb->nf_bridge->physoutdev->ifindex)); +			if (nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, +					 htonl(outdev->ifindex))) +				goto nla_put_failure; +			if (skb->nf_bridge && skb->nf_bridge->physoutdev && +			    nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, +					 htonl(skb->nf_bridge->physoutdev->ifindex))) +				goto nla_put_failure;  		}  #endif  	} -	if (skb->mark) -		NLA_PUT_BE32(inst->skb, NFULA_MARK, htonl(skb->mark)); +	if (skb->mark && +	    nla_put_be32(inst->skb, NFULA_MARK, htonl(skb->mark))) +		goto nla_put_failure; -	if (indev && skb->dev) { +	if (indev && skb->dev && +	    skb->mac_header != skb->network_header) {  		struct nfulnl_msg_packet_hw phw; -		int len = dev_parse_header(skb, phw.hw_addr); +		int len; + +		memset(&phw, 0, sizeof(phw)); +		len = dev_parse_header(skb, phw.hw_addr);  		if (len > 0) {  			phw.hw_addrlen = htons(len); -			NLA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); +			if (nla_put(inst->skb, NFULA_HWADDR, sizeof(phw), &phw)) +				goto nla_put_failure;  		}  	}  	if (indev && skb_mac_header_was_set(skb)) { -		NLA_PUT_BE16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)); -		NLA_PUT_BE16(inst->skb, NFULA_HWLEN, -			     htons(skb->dev->hard_header_len)); -		NLA_PUT(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len, -			skb_mac_header(skb)); +		if (nla_put_be16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) || +		    nla_put_be16(inst->skb, NFULA_HWLEN, +				 htons(skb->dev->hard_header_len))) +			goto nla_put_failure; + +		hwhdrp = skb_mac_header(skb); + +		if (skb->dev->type == ARPHRD_SIT) +			hwhdrp -= ETH_HLEN; + +		if (hwhdrp >= skb->head && +		    nla_put(inst->skb, NFULA_HWHEADER, +			    skb->dev->hard_header_len, hwhdrp)) +			goto nla_put_failure;  	}  	if (skb->tstamp.tv64) { @@ -482,32 +531,38 @@ __build_packet_message(struct nfulnl_instance *inst,  		ts.sec = cpu_to_be64(tv.tv_sec);  		ts.usec = cpu_to_be64(tv.tv_usec); -		NLA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts); +		if (nla_put(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts)) +			goto nla_put_failure;  	}  	/* UID */ -	if (skb->sk) { -		read_lock_bh(&skb->sk->sk_callback_lock); -		if (skb->sk->sk_socket && skb->sk->sk_socket->file) { -			struct file *file = skb->sk->sk_socket->file; -			__be32 uid = htonl(file->f_cred->fsuid); -			__be32 gid = htonl(file->f_cred->fsgid); -			/* need to unlock here since NLA_PUT may goto */ -			read_unlock_bh(&skb->sk->sk_callback_lock); -			NLA_PUT_BE32(inst->skb, NFULA_UID, uid); -			NLA_PUT_BE32(inst->skb, NFULA_GID, gid); +	sk = skb->sk; +	if (sk && sk->sk_state != TCP_TIME_WAIT) { +		read_lock_bh(&sk->sk_callback_lock); +		if (sk->sk_socket && sk->sk_socket->file) { +			struct file *file = sk->sk_socket->file; +			const struct cred *cred = file->f_cred; +			struct user_namespace *user_ns = inst->peer_user_ns; +			__be32 uid = htonl(from_kuid_munged(user_ns, cred->fsuid)); +			__be32 gid = htonl(from_kgid_munged(user_ns, cred->fsgid)); +			read_unlock_bh(&sk->sk_callback_lock); +			if (nla_put_be32(inst->skb, NFULA_UID, uid) || +			    nla_put_be32(inst->skb, NFULA_GID, gid)) +				goto nla_put_failure;  		} else -			read_unlock_bh(&skb->sk->sk_callback_lock); +			read_unlock_bh(&sk->sk_callback_lock);  	}  	/* local sequence number */ -	if (inst->flags & NFULNL_CFG_F_SEQ) -		NLA_PUT_BE32(inst->skb, NFULA_SEQ, htonl(inst->seq++)); +	if ((inst->flags & NFULNL_CFG_F_SEQ) && +	    nla_put_be32(inst->skb, NFULA_SEQ, htonl(inst->seq++))) +		goto nla_put_failure;  	/* global sequence number */ -	if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) -		NLA_PUT_BE32(inst->skb, NFULA_SEQ_GLOBAL, -			     htonl(atomic_inc_return(&global_seq))); +	if ((inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) && +	    nla_put_be32(inst->skb, NFULA_SEQ_GLOBAL, +			 htonl(atomic_inc_return(&log->global_seq)))) +		goto nla_put_failure;  	if (data_len) {  		struct nlattr *nla; @@ -515,7 +570,7 @@ __build_packet_message(struct nfulnl_instance *inst,  		if (skb_tailroom(inst->skb) < nla_total_size(data_len)) {  			printk(KERN_WARNING "nfnetlink_log: no tailroom!\n"); -			goto nlmsg_failure; +			return -1;  		}  		nla = (struct nlattr *)skb_put(inst->skb, nla_total_size(data_len)); @@ -529,7 +584,6 @@ __build_packet_message(struct nfulnl_instance *inst,  	nlh->nlmsg_len = inst->skb->tail - old_tail;  	return 0; -nlmsg_failure:  nla_put_failure:  	PRINTR(KERN_ERR "nfnetlink_log: error creating log nlmsg\n");  	return -1; @@ -550,7 +604,8 @@ static struct nf_loginfo default_loginfo = {  /* log handler for internal netfilter logging api */  void -nfulnl_log_packet(u_int8_t pf, +nfulnl_log_packet(struct net *net, +		  u_int8_t pf,  		  unsigned int hooknum,  		  const struct sk_buff *skb,  		  const struct net_device *in, @@ -563,13 +618,14 @@ nfulnl_log_packet(u_int8_t pf,  	const struct nf_loginfo *li;  	unsigned int qthreshold;  	unsigned int plen; +	struct nfnl_log_net *log = nfnl_log_pernet(net);  	if (li_user && li_user->type == NF_LOG_TYPE_ULOG)  		li = li_user;  	else  		li = &default_loginfo; -	inst = instance_lookup_get(li->u.ulog.group); +	inst = instance_lookup_get(log, li->u.ulog.group);  	if (!inst)  		return; @@ -580,7 +636,7 @@ nfulnl_log_packet(u_int8_t pf,  	/* FIXME: do we want to make the size calculation conditional based on  	 * what is actually present?  way more branches and checks, but more  	 * memory efficient... */ -	size =    NLMSG_SPACE(sizeof(struct nfgenmsg)) +	size =    nlmsg_total_size(sizeof(struct nfgenmsg))  		+ nla_total_size(sizeof(struct nfulnl_msg_packet_hdr))  		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */  		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */ @@ -644,15 +700,16 @@ nfulnl_log_packet(u_int8_t pf,  	}  	if (!inst->skb) { -		inst->skb = nfulnl_alloc_skb(inst->nlbufsiz, size); +		inst->skb = nfulnl_alloc_skb(net, inst->peer_portid, +					     inst->nlbufsiz, size);  		if (!inst->skb)  			goto alloc_failure;  	}  	inst->qlen++; -	__build_packet_message(inst, skb, data_len, pf, -				hooknum, in, out, li, prefix, plen); +	__build_packet_message(log, inst, skb, data_len, pf, +				hooknum, in, out, prefix, plen);  	if (inst->qlen >= qthreshold)  		__nfulnl_flush(inst); @@ -680,24 +737,24 @@ nfulnl_rcv_nl_event(struct notifier_block *this,  		   unsigned long event, void *ptr)  {  	struct netlink_notify *n = ptr; +	struct nfnl_log_net *log = nfnl_log_pernet(n->net);  	if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {  		int i; -		/* destroy all instances for this pid */ -		spin_lock_bh(&instances_lock); +		/* destroy all instances for this portid */ +		spin_lock_bh(&log->instances_lock);  		for  (i = 0; i < INSTANCE_BUCKETS; i++) { -			struct hlist_node *tmp, *t2; +			struct hlist_node *t2;  			struct nfulnl_instance *inst; -			struct hlist_head *head = &instance_table[i]; +			struct hlist_head *head = &log->instance_table[i]; -			hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { -				if ((net_eq(n->net, &init_net)) && -				    (n->pid == inst->peer_pid)) +			hlist_for_each_entry_safe(inst, t2, head, hlist) { +				if (n->portid == inst->peer_portid)  					__instance_destroy(inst);  			}  		} -		spin_unlock_bh(&instances_lock); +		spin_unlock_bh(&log->instances_lock);  	}  	return NOTIFY_DONE;  } @@ -734,10 +791,12 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,  		   const struct nlmsghdr *nlh,  		   const struct nlattr * const nfula[])  { -	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); +	struct nfgenmsg *nfmsg = nlmsg_data(nlh);  	u_int16_t group_num = ntohs(nfmsg->res_id);  	struct nfulnl_instance *inst;  	struct nfulnl_msg_config_cmd *cmd = NULL; +	struct net *net = sock_net(ctnl); +	struct nfnl_log_net *log = nfnl_log_pernet(net);  	int ret = 0;  	if (nfula[NFULA_CFG_CMD]) { @@ -747,15 +806,15 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,  		/* Commands without queue context */  		switch (cmd->command) {  		case NFULNL_CFG_CMD_PF_BIND: -			return nf_log_bind_pf(pf, &nfulnl_logger); +			return nf_log_bind_pf(net, pf, &nfulnl_logger);  		case NFULNL_CFG_CMD_PF_UNBIND: -			nf_log_unbind_pf(pf); +			nf_log_unbind_pf(net, pf);  			return 0;  		}  	} -	inst = instance_lookup_get(group_num); -	if (inst && inst->peer_pid != NETLINK_CB(skb).pid) { +	inst = instance_lookup_get(log, group_num); +	if (inst && inst->peer_portid != NETLINK_CB(skb).portid) {  		ret = -EPERM;  		goto out_put;  	} @@ -768,8 +827,9 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,  				goto out_put;  			} -			inst = instance_create(group_num, -					       NETLINK_CB(skb).pid); +			inst = instance_create(net, group_num, +					       NETLINK_CB(skb).portid, +					       sk_user_ns(NETLINK_CB(skb).sk));  			if (IS_ERR(inst)) {  				ret = PTR_ERR(inst);  				goto out; @@ -781,7 +841,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,  				goto out;  			} -			instance_destroy(inst); +			instance_destroy(log, inst);  			goto out_put;  		default:  			ret = -ENOTSUPP; @@ -864,55 +924,68 @@ static const struct nfnetlink_subsystem nfulnl_subsys = {  #ifdef CONFIG_PROC_FS  struct iter_state { +	struct seq_net_private p;  	unsigned int bucket;  }; -static struct hlist_node *get_first(struct iter_state *st) +static struct hlist_node *get_first(struct net *net, struct iter_state *st)  { +	struct nfnl_log_net *log;  	if (!st)  		return NULL; +	log = nfnl_log_pernet(net); +  	for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { -		if (!hlist_empty(&instance_table[st->bucket])) -			return rcu_dereference_bh(instance_table[st->bucket].first); +		struct hlist_head *head = &log->instance_table[st->bucket]; + +		if (!hlist_empty(head)) +			return rcu_dereference_bh(hlist_first_rcu(head));  	}  	return NULL;  } -static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h) +static struct hlist_node *get_next(struct net *net, struct iter_state *st, +				   struct hlist_node *h)  { -	h = rcu_dereference_bh(h->next); +	h = rcu_dereference_bh(hlist_next_rcu(h));  	while (!h) { +		struct nfnl_log_net *log; +		struct hlist_head *head; +  		if (++st->bucket >= INSTANCE_BUCKETS)  			return NULL; -		h = rcu_dereference_bh(instance_table[st->bucket].first); +		log = nfnl_log_pernet(net); +		head = &log->instance_table[st->bucket]; +		h = rcu_dereference_bh(hlist_first_rcu(head));  	}  	return h;  } -static struct hlist_node *get_idx(struct iter_state *st, loff_t pos) +static struct hlist_node *get_idx(struct net *net, struct iter_state *st, +				  loff_t pos)  {  	struct hlist_node *head; -	head = get_first(st); +	head = get_first(net, st);  	if (head) -		while (pos && (head = get_next(st, head))) +		while (pos && (head = get_next(net, st, head)))  			pos--;  	return pos ? NULL : head;  } -static void *seq_start(struct seq_file *seq, loff_t *pos) +static void *seq_start(struct seq_file *s, loff_t *pos)  	__acquires(rcu_bh)  {  	rcu_read_lock_bh(); -	return get_idx(seq->private, *pos); +	return get_idx(seq_file_net(s), s->private, *pos);  }  static void *seq_next(struct seq_file *s, void *v, loff_t *pos)  {  	(*pos)++; -	return get_next(s->private, v); +	return get_next(seq_file_net(s), s->private, v);  }  static void seq_stop(struct seq_file *s, void *v) @@ -927,7 +1000,7 @@ static int seq_show(struct seq_file *s, void *v)  	return seq_printf(s, "%5d %6d %5d %1d %5d %6d %2d\n",  			  inst->group_num, -			  inst->peer_pid, inst->qlen, +			  inst->peer_portid, inst->qlen,  			  inst->copy_mode, inst->copy_range,  			  inst->flushtimeout, atomic_read(&inst->use));  } @@ -941,8 +1014,8 @@ static const struct seq_operations nful_seq_ops = {  static int nful_open(struct inode *inode, struct file *file)  { -	return seq_open_private(file, &nful_seq_ops, -			sizeof(struct iter_state)); +	return seq_open_net(inode, file, &nful_seq_ops, +			    sizeof(struct iter_state));  }  static const struct file_operations nful_file_ops = { @@ -950,47 +1023,69 @@ static const struct file_operations nful_file_ops = {  	.open	 = nful_open,  	.read	 = seq_read,  	.llseek	 = seq_lseek, -	.release = seq_release_private, +	.release = seq_release_net,  };  #endif /* PROC_FS */ -static int __init nfnetlink_log_init(void) +static int __net_init nfnl_log_net_init(struct net *net)  { -	int i, status = -ENOMEM; +	unsigned int i; +	struct nfnl_log_net *log = nfnl_log_pernet(net);  	for (i = 0; i < INSTANCE_BUCKETS; i++) -		INIT_HLIST_HEAD(&instance_table[i]); +		INIT_HLIST_HEAD(&log->instance_table[i]); +	spin_lock_init(&log->instances_lock); + +#ifdef CONFIG_PROC_FS +	if (!proc_create("nfnetlink_log", 0440, +			 net->nf.proc_netfilter, &nful_file_ops)) +		return -ENOMEM; +#endif +	return 0; +} -	/* it's not really all that important to have a random value, so -	 * we can do this from the init function, even if there hasn't -	 * been that much entropy yet */ -	get_random_bytes(&hash_init, sizeof(hash_init)); +static void __net_exit nfnl_log_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS +	remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter); +#endif +	nf_log_unset(net, &nfulnl_logger); +} + +static struct pernet_operations nfnl_log_net_ops = { +	.init	= nfnl_log_net_init, +	.exit	= nfnl_log_net_exit, +	.id	= &nfnl_log_net_id, +	.size	= sizeof(struct nfnl_log_net), +}; + +static int __init nfnetlink_log_init(void) +{ +	int status = -ENOMEM;  	netlink_register_notifier(&nfulnl_rtnl_notifier);  	status = nfnetlink_subsys_register(&nfulnl_subsys);  	if (status < 0) { -		printk(KERN_ERR "log: failed to create netlink socket\n"); +		pr_err("log: failed to create netlink socket\n");  		goto cleanup_netlink_notifier;  	}  	status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger);  	if (status < 0) { -		printk(KERN_ERR "log: failed to register logger\n"); +		pr_err("log: failed to register logger\n");  		goto cleanup_subsys;  	} -#ifdef CONFIG_PROC_FS -	if (!proc_create("nfnetlink_log", 0440, -			 proc_net_netfilter, &nful_file_ops)) +	status = register_pernet_subsys(&nfnl_log_net_ops); +	if (status < 0) { +		pr_err("log: failed to register pernet ops\n");  		goto cleanup_logger; -#endif +	}  	return status; -#ifdef CONFIG_PROC_FS  cleanup_logger:  	nf_log_unregister(&nfulnl_logger); -#endif  cleanup_subsys:  	nfnetlink_subsys_unregister(&nfulnl_subsys);  cleanup_netlink_notifier: @@ -1000,10 +1095,8 @@ cleanup_netlink_notifier:  static void __exit nfnetlink_log_fini(void)  { +	unregister_pernet_subsys(&nfnl_log_net_ops);  	nf_log_unregister(&nfulnl_logger); -#ifdef CONFIG_PROC_FS -	remove_proc_entry("nfnetlink_log", proc_net_netfilter); -#endif  	nfnetlink_subsys_unregister(&nfulnl_subsys);  	netlink_unregister_notifier(&nfulnl_rtnl_notifier);  }  | 
