[NETFILTER]: Properly use RCU in nf_ct_attach

Use rcu_assign_pointer/rcu_dereference for ip_ct_attach pointer instead
of self-made RCU and use rcu_read_lock to make sure the conntrack module
doesn't disappear below us while calling it, since this function can be
called from outside the netfilter hooks.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 04e466d..508e600 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -1354,7 +1354,7 @@
    supposed to kill the mall. */
 void ip_conntrack_cleanup(void)
 {
-	ip_ct_attach = NULL;
+	rcu_assign_pointer(ip_ct_attach, NULL);
 
 	/* This makes sure all current packets have passed through
 	   netfilter framework.  Roll on, two-stage module
@@ -1515,7 +1515,7 @@
 	write_unlock_bh(&ip_conntrack_lock);
 
 	/* For use by ipt_REJECT */
-	ip_ct_attach = ip_conntrack_attach;
+	rcu_assign_pointer(ip_ct_attach, ip_conntrack_attach);
 
 	/* Set up fake conntrack:
 	    - to never be deleted, not in any hashes */
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 291b8c6..ad24d0c 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -248,9 +248,12 @@
 {
 	void (*attach)(struct sk_buff *, struct sk_buff *);
 
-	if (skb->nfct && (attach = ip_ct_attach) != NULL) {
-		mb(); /* Just to be sure: must be read before executing this */
-		attach(new, skb);
+	if (skb->nfct) {
+		rcu_read_lock();
+		attach = rcu_dereference(ip_ct_attach);
+		if (attach)
+			attach(new, skb);
+		rcu_read_unlock();
 	}
 }
 EXPORT_SYMBOL(nf_ct_attach);
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 9b02ec4..59bcab1 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1105,7 +1105,7 @@
 {
 	int i;
 
-	ip_ct_attach = NULL;
+	rcu_assign_pointer(ip_ct_attach, NULL);
 
 	/* This makes sure all current packets have passed through
 	   netfilter framework.  Roll on, two-stage module
@@ -1273,7 +1273,7 @@
         write_unlock_bh(&nf_conntrack_lock);
 
 	/* For use by REJECT target */
-	ip_ct_attach = __nf_conntrack_attach;
+	rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach);
 
 	/* Set up fake conntrack:
 	    - to never be deleted, not in any hashes */