[PATCH] net: ipv6: fix TCP early demux

Subsystems: networking [general], networking [tcp], the rest

STALE5096d

10 messages, 5 authors, 2012-08-19 · open the first message on its own page

[PATCH] net: ipv6: fix TCP early demux

From: Eric Dumazet <hidden>
Date: 2012-08-06 15:09:38

From: Eric Dumazet <edumazet@google.com>

IPv6 needs a cookie in dst_check() call.

We need to add rx_dst_cookie and provide a family independent
sk_rx_dst_set(sk, skb) method to properly support IPv6 TCP early demux.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
Note: we could group sk_rx_dst/rx_dst_ifindex/rx_dst_cookie
in same cache line (in sk)

 include/linux/ipv6.h               |    1 +
 include/net/inet_connection_sock.h |    1 +
 include/net/inet_sock.h            |    9 ---------
 net/ipv4/tcp_input.c               |    4 +++-
 net/ipv4/tcp_ipv4.c                |   13 ++++++++++---
 net/ipv4/tcp_minisocks.c           |    2 +-
 net/ipv6/tcp_ipv6.c                |   27 +++++++++++++++++++++++++--
 7 files changed, 41 insertions(+), 16 deletions(-)
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 379e433..879db26 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -369,6 +369,7 @@ struct ipv6_pinfo {
 	__u8			rcv_tclass;
 
 	__u32			dst_cookie;
+	__u32			rx_dst_cookie;
 
 	struct ipv6_mc_socklist	__rcu *ipv6_mc_list;
 	struct ipv6_ac_socklist	*ipv6_ac_list;
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index 5ee66f5..ba1d361 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -39,6 +39,7 @@ struct inet_connection_sock_af_ops {
 	int	    (*queue_xmit)(struct sk_buff *skb, struct flowi *fl);
 	void	    (*send_check)(struct sock *sk, struct sk_buff *skb);
 	int	    (*rebuild_header)(struct sock *sk);
+	void	    (*sk_rx_dst_set)(struct sock *sk, const struct sk_buff *skb);
 	int	    (*conn_request)(struct sock *sk, struct sk_buff *skb);
 	struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,
 				      struct request_sock *req,
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 83b567f..613cfa4 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -249,13 +249,4 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
 	return flags;
 }
 
-static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
-{
-	struct dst_entry *dst = skb_dst(skb);
-
-	dst_hold(dst);
-	sk->sk_rx_dst = dst;
-	inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
-}
-
 #endif	/* _INET_SOCK_H */
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 2fd2bc9..85308b9 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5392,6 +5392,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
+	if (unlikely(sk->sk_rx_dst == NULL))
+		inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb);
 	/*
 	 *	Header prediction.
 	 *	The code loosely follows the one in the famous
@@ -5605,7 +5607,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
 	tcp_set_state(sk, TCP_ESTABLISHED);
 
 	if (skb != NULL) {
-		inet_sk_rx_dst_set(sk, skb);
+		icsk->icsk_af_ops->sk_rx_dst_set(sk, skb);
 		security_inet_conn_established(sk, skb);
 	}
 
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 42b2a6a..272241f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1627,9 +1627,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
 				sk->sk_rx_dst = NULL;
 			}
 		}
-		if (unlikely(sk->sk_rx_dst == NULL))
-			inet_sk_rx_dst_set(sk, skb);
-
 		if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
 			rsk = sk;
 			goto reset;
@@ -1872,10 +1869,20 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
 	.twsk_destructor= tcp_twsk_destructor,
 };
 
+static void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
+{
+	struct dst_entry *dst = skb_dst(skb);
+
+	dst_hold(dst);
+	sk->sk_rx_dst = dst;
+	inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+}
+
 const struct inet_connection_sock_af_ops ipv4_specific = {
 	.queue_xmit	   = ip_queue_xmit,
 	.send_check	   = tcp_v4_send_check,
 	.rebuild_header	   = inet_sk_rebuild_header,
+	.sk_rx_dst_set	   = inet_sk_rx_dst_set,
 	.conn_request	   = tcp_v4_conn_request,
 	.syn_recv_sock	   = tcp_v4_syn_recv_sock,
 	.net_header_len	   = sizeof(struct iphdr),
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 232a90c..d9c9dce 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -387,7 +387,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
 		struct tcp_sock *oldtp = tcp_sk(sk);
 		struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
 
-		inet_sk_rx_dst_set(newsk, skb);
+		newicsk->icsk_af_ops->sk_rx_dst_set(newsk, skb);
 
 		/* TCP Cookie Transactions require space for the cookie pair,
 		 * as it differs for each connection.  There is no need to
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c66b90f..5a439e9 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1447,7 +1447,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
 		opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC));
 
 	if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
+		struct dst_entry *dst = sk->sk_rx_dst;
+
 		sock_rps_save_rxhash(sk, skb);
+		if (dst) {
+			if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
+			    dst->ops->check(dst, np->rx_dst_cookie) == NULL) {
+				dst_release(dst);
+				sk->sk_rx_dst = NULL;
+			}
+		}
+
 		if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
 			goto reset;
 		if (opt_skb)
@@ -1705,9 +1715,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
 			struct dst_entry *dst = sk->sk_rx_dst;
 			struct inet_sock *icsk = inet_sk(sk);
 			if (dst)
-				dst = dst_check(dst, 0);
+				dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
 			if (dst &&
-			    icsk->rx_dst_ifindex == inet6_iif(skb))
+			    icsk->rx_dst_ifindex == skb->skb_iif)
 				skb_dst_set_noref(skb, dst);
 		}
 	}
@@ -1719,10 +1729,23 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = {
 	.twsk_destructor= tcp_twsk_destructor,
 };
 
+static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
+{
+	struct dst_entry *dst = skb_dst(skb);
+	const struct rt6_info *rt = (const struct rt6_info *)dst;
+
+	dst_hold(dst);
+	sk->sk_rx_dst = dst;
+	inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+	if (rt->rt6i_node)
+		inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
+}
+
 static const struct inet_connection_sock_af_ops ipv6_specific = {
 	.queue_xmit	   = inet6_csk_xmit,
 	.send_check	   = tcp_v6_send_check,
 	.rebuild_header	   = inet6_sk_rebuild_header,
+	.sk_rx_dst_set	   = inet6_sk_rx_dst_set,
 	.conn_request	   = tcp_v6_conn_request,
 	.syn_recv_sock	   = tcp_v6_syn_recv_sock,
 	.net_header_len	   = sizeof(struct ipv6hdr),

Re: [PATCH] net: ipv6: fix TCP early demux

From: David Miller <davem@davemloft.net>
Date: 2012-08-06 20:33:44

From: Eric Dumazet <redacted>
Date: Mon, 06 Aug 2012 17:09:33 +0200
From: Eric Dumazet <edumazet@google.com>

IPv6 needs a cookie in dst_check() call.

We need to add rx_dst_cookie and provide a family independent
sk_rx_dst_set(sk, skb) method to properly support IPv6 TCP early demux.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied, thanks.
---
Note: we could group sk_rx_dst/rx_dst_ifindex/rx_dst_cookie
in same cache line (in sk)
I don't think this is necessary, for now.

Re: [PATCH] net: ipv6: fix TCP early demux

From: Andrew Morton <akpm@linux-foundation.org>
Date: 2012-08-09 23:03:51

On Mon, 06 Aug 2012 17:09:33 +0200
Eric Dumazet [off-list ref] wrote:
IPv6 needs a cookie in dst_check() call.

We need to add rx_dst_cookie and provide a family independent
sk_rx_dst_set(sk, skb) method to properly support IPv6 TCP early demux.
My test box is oopsing late in initscripts.  Current mainline, config
at http://ozlabs.org/~akpm/stuff/config-akpm2.

It looks like icsk->icsk_af_ops->sk_rx_dst_set is NULL.  Reverting this
patch fixes things up.


[   67.422369] SELinux: initialized (dev autofs, type autofs), uses genfs_contexts
[   67.449678] SELinux: initialized (dev autofs, type autofs), uses genfs_contexts
[   92.631060] BUG: unable to handle kernel NULL pointer dereference at           (null)
[   92.631435] IP: [<          (null)>]           (null)
[   92.631645] PGD 0 
[   92.631846] Oops: 0010 [#1] SMP 
[   92.632095] Modules linked in: autofs4 sunrpc ipv6 dm_mirror dm_region_hash dm_log dm_multipath dm_mod video sbs sbshc battery ac lp parport sg snd_hda_intel snd_hda_codec snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device pcspkr snd_pcm_oss snd_mixer_oss snd_pcm snd_timer serio_raw button floppy snd i2c_i801 i2c_core soundcore snd_page_alloc shpchp ide_cd_mod cdrom microcode ehci_hcd ohci_hcd uhci_hcd
[   92.634294] CPU 0 
[   92.634294] Pid: 4469, comm: sendmail Not tainted 3.6.0-rc1 #3  
[   92.634294] RIP: 0010:[<0000000000000000>]  [<          (null)>]           (null)
[   92.634294] RSP: 0018:ffff880245fc7cb0  EFLAGS: 00010282
[   92.634294] RAX: ffffffffa01985f0 RBX: ffff88024827ad00 RCX: 0000000000000000
[   92.634294] RDX: 0000000000000218 RSI: ffff880254735380 RDI: ffff88024827ad00
[   92.634294] RBP: ffff880245fc7cc8 R08: 0000000000000001 R09: 0000000000000000
[   92.634294] R10: 0000000000000000 R11: ffff880245fc7bf8 R12: ffff880254735380
[   92.634294] R13: ffff880254735380 R14: 0000000000000000 R15: 7fffffffffff0218
[   92.634294] FS:  00007f4516ccd6f0(0000) GS:ffff880256600000(0000) knlGS:0000000000000000
[   92.634294] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[   92.634294] CR2: 0000000000000000 CR3: 0000000245ed1000 CR4: 00000000000007f0
[   92.634294] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   92.634294] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[   92.634294] Process sendmail (pid: 4469, threadinfo ffff880245fc6000, task ffff880254b8cac0)
[   92.634294] Stack:
[   92.634294]  ffffffff813837a7 ffff88024827ad00 ffff880254b6b0e8 ffff880245fc7d68
[   92.634294]  ffffffff81385083 00000000001d2680 ffff8802547353a8 ffff880245fc7d18
[   92.634294]  ffffffff8105903a ffff88024827ad60 0000000000000002 00000000000000ff
[   92.634294] Call Trace:
[   92.634294]  [<ffffffff813837a7>] ? tcp_finish_connect+0x2c/0xfa
[   92.634294]  [<ffffffff81385083>] tcp_rcv_state_process+0x2b6/0x9c6
[   92.634294]  [<ffffffff8105903a>] ? sched_clock_cpu+0xc3/0xd1
[   92.634294]  [<ffffffff81059073>] ? local_clock+0x2b/0x3c
[   92.634294]  [<ffffffff8138caf3>] tcp_v4_do_rcv+0x63a/0x670
[   92.634294]  [<ffffffff8133278e>] release_sock+0x128/0x1bd
[   92.634294]  [<ffffffff8139f060>] __inet_stream_connect+0x1b1/0x352
[   92.634294]  [<ffffffff813325f5>] ? lock_sock_nested+0x74/0x7f
[   92.634294]  [<ffffffff8104b333>] ? wake_up_bit+0x25/0x25
[   92.634294]  [<ffffffff813325f5>] ? lock_sock_nested+0x74/0x7f
[   92.634294]  [<ffffffff8139f223>] ? inet_stream_connect+0x22/0x4b
[   92.634294]  [<ffffffff8139f234>] inet_stream_connect+0x33/0x4b
[   92.634294]  [<ffffffff8132e8cf>] sys_connect+0x78/0x9e
[   92.634294]  [<ffffffff813fd407>] ? sysret_check+0x1b/0x56
[   92.634294]  [<ffffffff81088503>] ? __audit_syscall_entry+0x195/0x1c8
[   92.634294]  [<ffffffff811cc26e>] ? trace_hardirqs_on_thunk+0x3a/0x3f
[   92.634294]  [<ffffffff813fd3e2>] system_call_fastpath+0x16/0x1b
[   92.634294] Code:  Bad RIP value.
[   92.634294] RIP  [<          (null)>]           (null)
[   92.634294]  RSP <ffff880245fc7cb0>
[   92.634294] CR2: 0000000000000000
[   92.648982] ---[ end trace 24e2bed94314c8d9 ]---
[   92.649146] Kernel panic - not syncing: Fatal exception in interrupt

Re: [PATCH] net: ipv6: fix TCP early demux

From: Eric Dumazet <hidden>
Date: 2012-08-09 23:58:58

On Thu, 2012-08-09 at 16:03 -0700, Andrew Morton wrote:
On Mon, 06 Aug 2012 17:09:33 +0200
Eric Dumazet [off-list ref] wrote:
quoted
IPv6 needs a cookie in dst_check() call.

We need to add rx_dst_cookie and provide a family independent
sk_rx_dst_set(sk, skb) method to properly support IPv6 TCP early demux.
My test box is oopsing late in initscripts.  Current mainline, config
at http://ozlabs.org/~akpm/stuff/config-akpm2.

It looks like icsk->icsk_af_ops->sk_rx_dst_set is NULL.  Reverting this
patch fixes things up.


[   67.422369] SELinux: initialized (dev autofs, type autofs), uses genfs_contexts
[   67.449678] SELinux: initialized (dev autofs, type autofs), uses genfs_contexts
[   92.631060] BUG: unable to handle kernel NULL pointer dereference at           (null)
[   92.631435] IP: [<          (null)>]           (null)
[   92.631645] PGD 0 
[   92.631846] Oops: 0010 [#1] SMP 
[   92.632095] Modules linked in: autofs4 sunrpc ipv6 dm_mirror dm_region_hash dm_log dm_multipath dm_mod video sbs sbshc battery ac lp parport sg snd_hda_intel snd_hda_codec snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device pcspkr snd_pcm_oss snd_mixer_oss snd_pcm snd_timer serio_raw button floppy snd i2c_i801 i2c_core soundcore snd_page_alloc shpchp ide_cd_mod cdrom microcode ehci_hcd ohci_hcd uhci_hcd
[   92.634294] CPU 0 
[   92.634294] Pid: 4469, comm: sendmail Not tainted 3.6.0-rc1 #3  
[   92.634294] RIP: 0010:[<0000000000000000>]  [<          (null)>]           (null)
[   92.634294] RSP: 0018:ffff880245fc7cb0  EFLAGS: 00010282
[   92.634294] RAX: ffffffffa01985f0 RBX: ffff88024827ad00 RCX: 0000000000000000
[   92.634294] RDX: 0000000000000218 RSI: ffff880254735380 RDI: ffff88024827ad00
[   92.634294] RBP: ffff880245fc7cc8 R08: 0000000000000001 R09: 0000000000000000
[   92.634294] R10: 0000000000000000 R11: ffff880245fc7bf8 R12: ffff880254735380
[   92.634294] R13: ffff880254735380 R14: 0000000000000000 R15: 7fffffffffff0218
[   92.634294] FS:  00007f4516ccd6f0(0000) GS:ffff880256600000(0000) knlGS:0000000000000000
[   92.634294] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[   92.634294] CR2: 0000000000000000 CR3: 0000000245ed1000 CR4: 00000000000007f0
[   92.634294] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   92.634294] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[   92.634294] Process sendmail (pid: 4469, threadinfo ffff880245fc6000, task ffff880254b8cac0)
[   92.634294] Stack:
[   92.634294]  ffffffff813837a7 ffff88024827ad00 ffff880254b6b0e8 ffff880245fc7d68
[   92.634294]  ffffffff81385083 00000000001d2680 ffff8802547353a8 ffff880245fc7d18
[   92.634294]  ffffffff8105903a ffff88024827ad60 0000000000000002 00000000000000ff
[   92.634294] Call Trace:
[   92.634294]  [<ffffffff813837a7>] ? tcp_finish_connect+0x2c/0xfa
[   92.634294]  [<ffffffff81385083>] tcp_rcv_state_process+0x2b6/0x9c6
[   92.634294]  [<ffffffff8105903a>] ? sched_clock_cpu+0xc3/0xd1
[   92.634294]  [<ffffffff81059073>] ? local_clock+0x2b/0x3c
[   92.634294]  [<ffffffff8138caf3>] tcp_v4_do_rcv+0x63a/0x670
[   92.634294]  [<ffffffff8133278e>] release_sock+0x128/0x1bd
[   92.634294]  [<ffffffff8139f060>] __inet_stream_connect+0x1b1/0x352
[   92.634294]  [<ffffffff813325f5>] ? lock_sock_nested+0x74/0x7f
[   92.634294]  [<ffffffff8104b333>] ? wake_up_bit+0x25/0x25
[   92.634294]  [<ffffffff813325f5>] ? lock_sock_nested+0x74/0x7f
[   92.634294]  [<ffffffff8139f223>] ? inet_stream_connect+0x22/0x4b
[   92.634294]  [<ffffffff8139f234>] inet_stream_connect+0x33/0x4b
[   92.634294]  [<ffffffff8132e8cf>] sys_connect+0x78/0x9e
[   92.634294]  [<ffffffff813fd407>] ? sysret_check+0x1b/0x56
[   92.634294]  [<ffffffff81088503>] ? __audit_syscall_entry+0x195/0x1c8
[   92.634294]  [<ffffffff811cc26e>] ? trace_hardirqs_on_thunk+0x3a/0x3f
[   92.634294]  [<ffffffff813fd3e2>] system_call_fastpath+0x16/0x1b
[   92.634294] Code:  Bad RIP value.
[   92.634294] RIP  [<          (null)>]           (null)
[   92.634294]  RSP <ffff880245fc7cb0>
[   92.634294] CR2: 0000000000000000
[   92.648982] ---[ end trace 24e2bed94314c8d9 ]---
[   92.649146] Kernel panic - not syncing: Fatal exception in interrupt
Oops, it seems I missed ipv6_mapped

Thanks Andrew, I'll send a fix

[PATCH] net: tcp: ipv6_mapped needs sk_rx_dst_set method

From: Eric Dumazet <hidden>
Date: 2012-08-10 00:11:10

From: Eric Dumazet <edumazet@google.com>

commit 5d299f3d3c8a2fb (net: ipv6: fix TCP early demux) added a
regression for ipv6_mapped case.

[   67.422369] SELinux: initialized (dev autofs, type autofs), uses
genfs_contexts
[   67.449678] SELinux: initialized (dev autofs, type autofs), uses
genfs_contexts
[   92.631060] BUG: unable to handle kernel NULL pointer dereference at
(null)
[   92.631435] IP: [<          (null)>]           (null)
[   92.631645] PGD 0 
[   92.631846] Oops: 0010 [#1] SMP 
[   92.632095] Modules linked in: autofs4 sunrpc ipv6 dm_mirror
dm_region_hash dm_log dm_multipath dm_mod video sbs sbshc battery ac lp
parport sg snd_hda_intel snd_hda_codec snd_seq_oss snd_seq_midi_event
snd_seq snd_seq_device pcspkr snd_pcm_oss snd_mixer_oss snd_pcm
snd_timer serio_raw button floppy snd i2c_i801 i2c_core soundcore
snd_page_alloc shpchp ide_cd_mod cdrom microcode ehci_hcd ohci_hcd
uhci_hcd
[   92.634294] CPU 0 
[   92.634294] Pid: 4469, comm: sendmail Not tainted 3.6.0-rc1 #3  
[   92.634294] RIP: 0010:[<0000000000000000>]  [<          (null)>]
(null)
[   92.634294] RSP: 0018:ffff880245fc7cb0  EFLAGS: 00010282
[   92.634294] RAX: ffffffffa01985f0 RBX: ffff88024827ad00 RCX:
0000000000000000
[   92.634294] RDX: 0000000000000218 RSI: ffff880254735380 RDI:
ffff88024827ad00
[   92.634294] RBP: ffff880245fc7cc8 R08: 0000000000000001 R09:
0000000000000000
[   92.634294] R10: 0000000000000000 R11: ffff880245fc7bf8 R12:
ffff880254735380
[   92.634294] R13: ffff880254735380 R14: 0000000000000000 R15:
7fffffffffff0218
[   92.634294] FS:  00007f4516ccd6f0(0000) GS:ffff880256600000(0000)
knlGS:0000000000000000
[   92.634294] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[   92.634294] CR2: 0000000000000000 CR3: 0000000245ed1000 CR4:
00000000000007f0
[   92.634294] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   92.634294] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7:
0000000000000400
[   92.634294] Process sendmail (pid: 4469, threadinfo ffff880245fc6000,
task ffff880254b8cac0)
[   92.634294] Stack:
[   92.634294]  ffffffff813837a7 ffff88024827ad00 ffff880254b6b0e8
ffff880245fc7d68
[   92.634294]  ffffffff81385083 00000000001d2680 ffff8802547353a8
ffff880245fc7d18
[   92.634294]  ffffffff8105903a ffff88024827ad60 0000000000000002
00000000000000ff
[   92.634294] Call Trace:
[   92.634294]  [<ffffffff813837a7>] ? tcp_finish_connect+0x2c/0xfa
[   92.634294]  [<ffffffff81385083>] tcp_rcv_state_process+0x2b6/0x9c6
[   92.634294]  [<ffffffff8105903a>] ? sched_clock_cpu+0xc3/0xd1
[   92.634294]  [<ffffffff81059073>] ? local_clock+0x2b/0x3c
[   92.634294]  [<ffffffff8138caf3>] tcp_v4_do_rcv+0x63a/0x670
[   92.634294]  [<ffffffff8133278e>] release_sock+0x128/0x1bd
[   92.634294]  [<ffffffff8139f060>] __inet_stream_connect+0x1b1/0x352
[   92.634294]  [<ffffffff813325f5>] ? lock_sock_nested+0x74/0x7f
[   92.634294]  [<ffffffff8104b333>] ? wake_up_bit+0x25/0x25
[   92.634294]  [<ffffffff813325f5>] ? lock_sock_nested+0x74/0x7f
[   92.634294]  [<ffffffff8139f223>] ? inet_stream_connect+0x22/0x4b
[   92.634294]  [<ffffffff8139f234>] inet_stream_connect+0x33/0x4b
[   92.634294]  [<ffffffff8132e8cf>] sys_connect+0x78/0x9e
[   92.634294]  [<ffffffff813fd407>] ? sysret_check+0x1b/0x56
[   92.634294]  [<ffffffff81088503>] ? __audit_syscall_entry+0x195/0x1c8
[   92.634294]  [<ffffffff811cc26e>] ? trace_hardirqs_on_thunk+0x3a/0x3f
[   92.634294]  [<ffffffff813fd3e2>] system_call_fastpath+0x16/0x1b
[   92.634294] Code:  Bad RIP value.
[   92.634294] RIP  [<          (null)>]           (null)
[   92.634294]  RSP <ffff880245fc7cb0>
[   92.634294] CR2: 0000000000000000
[   92.648982] ---[ end trace 24e2bed94314c8d9 ]---
[   92.649146] Kernel panic - not syncing: Fatal exception in interrupt

Fix this using inet_sk_rx_dst_set(), and export this function in case
IPv6 is modular.

Reported-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 include/net/tcp.h   |    1 +
 net/ipv4/tcp_ipv4.c |    3 ++-
 net/ipv6/tcp_ipv6.c |    1 +
 3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index e19124b..1f000ff 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -464,6 +464,7 @@ extern int tcp_disconnect(struct sock *sk, int flags);
 void tcp_connect_init(struct sock *sk);
 void tcp_finish_connect(struct sock *sk, struct sk_buff *skb);
 int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size);
+void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb);
 
 /* From syncookies.c */
 extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 272241f..7678237 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1869,7 +1869,7 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
 	.twsk_destructor= tcp_twsk_destructor,
 };
 
-static void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
+void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb_dst(skb);
 
@@ -1877,6 +1877,7 @@ static void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 	sk->sk_rx_dst = dst;
 	inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
 }
+EXPORT_SYMBOL(inet_sk_rx_dst_set);
 
 const struct inet_connection_sock_af_ops ipv4_specific = {
 	.queue_xmit	   = ip_queue_xmit,
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5a439e9..bb9ce2b 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1777,6 +1777,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = {
 	.queue_xmit	   = ip_queue_xmit,
 	.send_check	   = tcp_v4_send_check,
 	.rebuild_header	   = inet_sk_rebuild_header,
+	.sk_rx_dst_set	   = inet_sk_rx_dst_set,
 	.conn_request	   = tcp_v6_conn_request,
 	.syn_recv_sock	   = tcp_v6_syn_recv_sock,
 	.net_header_len	   = sizeof(struct iphdr),

Re: [PATCH] net: tcp: ipv6_mapped needs sk_rx_dst_set method

From: David Miller <davem@davemloft.net>
Date: 2012-08-10 04:06:01

From: Eric Dumazet <redacted>
Date: Fri, 10 Aug 2012 02:11:00 +0200
From: Eric Dumazet <edumazet@google.com>

commit 5d299f3d3c8a2fb (net: ipv6: fix TCP early demux) added a
regression for ipv6_mapped case.
 ...
Fix this using inet_sk_rx_dst_set(), and export this function in case
IPv6 is modular.

Reported-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied.

Re: [PATCH] net: tcp: ipv6_mapped needs sk_rx_dst_set method

From: Artem Savkov <hidden>
Date: 2012-08-18 13:06:50

On Thu, Aug 09, 2012 at 09:06:00PM -0700, David Miller wrote:
From: Eric Dumazet <redacted>
Date: Fri, 10 Aug 2012 02:11:00 +0200
quoted
From: Eric Dumazet <edumazet@google.com>

commit 5d299f3d3c8a2fb (net: ipv6: fix TCP early demux) added a
regression for ipv6_mapped case.
 ...
quoted
Fix this using inet_sk_rx_dst_set(), and export this function in case
IPv6 is modular.

Reported-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied.
It doesn't seem to fix the problem with mapped ipv6 completely.
I'm still hitting a NULL pointer dereference with mapped ipv6:

[ 1699.191775] BUG: unable to handle kernel NULL pointer dereference at 00000016
[ 1699.192083] IP: [<c15d11d0>] inet6_sk_rx_dst_set+0x40/0xa0
[ 1699.192290] *pde = 00000000 
[ 1699.192455] Oops: 0000 [#1] SMP 
[ 1699.192686] Modules linked in: netconsole fuse iwldvm mac80211 btusb bluetooth kvm_intel iwlwifi cpufreq_ondemand kvm cfg80211 acpi_cpufreq mperf freq_table lpc_ich joydev crc32c_intel r8169 thermal thinkpad_acpi battery ac intel_ips processor
[ 1699.194710] Pid: 9823, comm: ncmpcpp Not tainted 3.6.0-rc1-next-20120810 #96 LENOVO 0578A21/0578A21
[ 1699.194896] EIP: 0060:[<c15d11d0>] EFLAGS: 00210202 CPU: 0
[ 1699.195040] EIP is at inet6_sk_rx_dst_set+0x40/0xa0
[ 1699.195176] EAX: 00000002 EBX: ef880780 ECX: f3264700 EDX: efc18e54
[ 1699.195325] ESI: edb01540 EDI: 00000000 EBP: f540dce8 ESP: f540dce0
[ 1699.195473]  DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
[ 1699.195610] CR0: 8005003b CR2: 00000016 CR3: 2d61a000 CR4: 000007d0
[ 1699.195757] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
[ 1699.195904] DR6: ffff0ff0 DR7: 00000400
[ 1699.196025] Process ncmpcpp (pid: 9823, ti=f540c000 task=eca26680 task.ti=e5354000)
[ 1699.196189] Stack:
[ 1699.196280]  ef880780 f3264c80 f540dd04 c15662a1 edb01540 efc18780 efc18780 f3264c80
[ 1699.197242]  efc18780 f540dd2c c1563b54 3401a499 3a200680 34932749 00d00680 edb01540
[ 1699.197933]  efc18780 f3264c80 c16c0de0 f540dd9c c15d162e 00000000 c12691d1 f540dd54
[ 1699.198630] Call Trace:
[ 1699.198736]  [<c15662a1>] tcp_create_openreq_child+0x41/0x4e0
[ 1699.198884]  [<c1563b54>] tcp_v4_syn_recv_sock+0x34/0x330
[ 1699.199032]  [<c15d162e>] tcp_v6_syn_recv_sock+0x3fe/0x660
[ 1699.199178]  [<c12691d1>] ? selinux_sock_rcv_skb_compat+0xb1/0xc0
[ 1699.199332]  [<c106c95d>] ? sched_clock_cpu+0xfd/0x180
[ 1699.199474]  [<c1566b76>] tcp_check_req+0x2b6/0x410
[ 1699.199610]  [<c1564756>] tcp_v4_do_rcv+0x266/0x420
[ 1699.199746]  [<c15659a2>] ? tcp_v4_rcv+0x732/0xb20
[ 1699.199881]  [<c162e25a>] ? _raw_spin_lock_nested+0x6a/0x80
[ 1699.200031]  [<c1565c9d>] tcp_v4_rcv+0xa2d/0xb20
[ 1699.200167]  [<c1541e0a>] ip_local_deliver_finish+0xda/0x370
[ 1699.200312]  [<c1541d6c>] ? ip_local_deliver_finish+0x3c/0x370
[ 1699.200460]  [<c15426cf>] ip_local_deliver+0x7f/0x90
[ 1699.200597]  [<c1541d30>] ? inet_del_protocol+0x40/0x40
[ 1699.200737]  [<c15421c2>] ip_rcv_finish+0x122/0x4a0
[ 1699.200873]  [<c1542965>] ip_rcv+0x285/0x370
[ 1699.201005]  [<c15420a0>] ? ip_local_deliver_finish+0x370/0x370
[ 1699.201156]  [<c1503b30>] __netif_receive_skb+0x540/0x790
[ 1699.201298]  [<c15036e1>] ? __netif_receive_skb+0xf1/0x790
[ 1699.201442]  [<c1503e13>] process_backlog+0x93/0x150
[ 1699.201578]  [<c1504915>] net_rx_action+0x105/0x1d0
[ 1699.201716]  [<c103d72f>] __do_softirq+0x9f/0x1d0
[ 1699.201854]  [<c103d690>] ? local_bh_enable_ip+0x90/0x90
[ 1699.202260]  <IRQ> 
[ 1699.202397] [<c103d679>] ? local_bh_enable_ip+0x79/0x90
[ 1699.202682]  [<c162ec35>] ? _raw_spin_unlock_bh+0x35/0x40
[ 1699.202826]  [<c14f3cbc>] ? release_sock+0x14c/0x1c0
[ 1699.205792]  [<c157537f>] ? inet_stream_connect+0x3f/0x50
[ 1699.208723]  [<c14f07c2>] ? sys_connect+0xb2/0xd0
[ 1699.211642]  [<c1125b9c>] ? fd_install+0x4c/0x60
[ 1699.214583]  [<c162ecf2>] ? _raw_spin_unlock+0x22/0x30
[ 1699.217400]  [<c1125b9c>] ? fd_install+0x4c/0x60
[ 1699.220080]  [<c14ee794>] ? sock_map_fd+0x24/0x30
[ 1699.222690]  [<c12b33e2>] ? _copy_from_user+0x52/0x70
[ 1699.225259]  [<c14f134f>] ? sys_socketcall+0xef/0x2d0
[ 1699.227803]  [<c105eceb>] ? up_write+0x1b/0x30
[ 1699.230325]  [<c16355cc>] ? sysenter_do_call+0x12/0x2d
[ 1699.232835] Code: c3 89 d6 f6 c1 01 75 33 83 e1 fe f0 ff 41 40 89 8b 10 01 00 00 8b 46 74 89 83 fc 02 00 00 8b 41 58 85 c0 74 0c 8b 93 d0 02 00 00 <8b> 40 14 89 42 68 8b 5d f8 8b 75 fc 89 ec 5d c3 e8 cb 21 a8 ff 
[ 1699.242913] EIP: [<c15d11d0>] inet6_sk_rx_dst_set+0x40/0xa0 SS:ESP 0068:f540dce0
[ 1699.245945] CR2: 0000000000000016
[ 1699.280708] ---[ end trace 3fb05aeec95e7238 ]---
[ 1699.280806] Kernel panic - not syncing: Fatal exception in interrupt
[ 1699.284674] panic occurred, switching back to text console

After some debugging I found out that rt->rt6i_node in inet6_sk_rx_dst_set
is 0x02 when this happens.

I've been able to fix this with:
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 4d63dff..a10a436 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1198,6 +1198,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                 *      v6 mapped
                 */
 
+               inet_csk(sk)->icsk_af_ops = &ipv6_mapped;
                newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
 
                if (newsk == NULL)
@@ -1218,7 +1219,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
                newnp->rcv_saddr = newnp->saddr;
 
-               inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
                newsk->sk_backlog_rcv = tcp_v4_do_rcv;
 #ifdef CONFIG_TCP_MD5SIG
                newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
But not sure if this is safe. Is it better to add some kind of
additional check to inet6_sk_rx_dst_set?


-- 
Kind regards,
Artem

Re: [PATCH] net: tcp: ipv6_mapped needs sk_rx_dst_set method

From: Neal Cardwell <ncardwell@google.com>
Date: 2012-08-19 04:06:34

On Sat, Aug 18, 2012 at 9:06 AM, Artem Savkov [off-list ref] wrote:
[ 1699.195040] EIP is at inet6_sk_rx_dst_set+0x40/0xa0
...
[ 1699.198736]  [<c15662a1>] tcp_create_openreq_child+0x41/0x4e0
[ 1699.198884]  [<c1563b54>] tcp_v4_syn_recv_sock+0x34/0x330
[ 1699.199032]  [<c15d162e>] tcp_v6_syn_recv_sock+0x3fe/0x660
...
quoted hunk
[ 1699.242913] EIP: [<c15d11d0>] inet6_sk_rx_dst_set+0x40/0xa0 SS:ESP 0068:f540dce0
[ 1699.245945] CR2: 0000000000000016
[ 1699.280708] ---[ end trace 3fb05aeec95e7238 ]---
[ 1699.280806] Kernel panic - not syncing: Fatal exception in interrupt
[ 1699.284674] panic occurred, switching back to text console

After some debugging I found out that rt->rt6i_node in inet6_sk_rx_dst_set
is 0x02 when this happens.

I've been able to fix this with:
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 4d63dff..a10a436 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1198,6 +1198,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                 *      v6 mapped
                 */

+               inet_csk(sk)->icsk_af_ops = &ipv6_mapped;
                newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);

                if (newsk == NULL)
@@ -1218,7 +1219,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,

                newnp->rcv_saddr = newnp->saddr;

-               inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
                newsk->sk_backlog_rcv = tcp_v4_do_rcv;
 #ifdef CONFIG_TCP_MD5SIG
                newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
But not sure if this is safe. Is it better to add some kind of
additional check to inet6_sk_rx_dst_set?
Thanks for the detailed report!

I don't think that particular fix is kosher, since this basically
changes the address family ops of the parent listening socket ('sk'
here).The parent listening socket needs to keep its IPv6 af_ops so its
IPv6 children can get the right af_ops.

We should probably either: (a) make sure the af_ops of the child
socket are set correctly earlier, or (b) not use dynamic dispatch
through the af_ops within tcp_create_openreq_child(), and just do the
sk_rx_dst_set a tiny bit later. I've sent out a patch for approach (b)
here, since it's simpler:

  http://patchwork.ozlabs.org/patch/178525/

I've verified that IPv4, IPv6, and IPv4-mapped-IPv6 connections work
for me with this patch. But if you could test it as well, that would
be great.

Thanks!
neal

Re: [PATCH] net: tcp: ipv6_mapped needs sk_rx_dst_set method

From: Artem Savkov <hidden>
Date: 2012-08-19 08:11:45

On Sun, Aug 19, 2012 at 12:06:33AM -0400, Neal Cardwell wrote:
On Sat, Aug 18, 2012 at 9:06 AM, Artem Savkov [off-list ref] wrote:
quoted
[ 1699.195040] EIP is at inet6_sk_rx_dst_set+0x40/0xa0
...
quoted
[ 1699.198736]  [<c15662a1>] tcp_create_openreq_child+0x41/0x4e0
[ 1699.198884]  [<c1563b54>] tcp_v4_syn_recv_sock+0x34/0x330
[ 1699.199032]  [<c15d162e>] tcp_v6_syn_recv_sock+0x3fe/0x660
...
quoted
[ 1699.242913] EIP: [<c15d11d0>] inet6_sk_rx_dst_set+0x40/0xa0 SS:ESP 0068:f540dce0
[ 1699.245945] CR2: 0000000000000016
[ 1699.280708] ---[ end trace 3fb05aeec95e7238 ]---
[ 1699.280806] Kernel panic - not syncing: Fatal exception in interrupt
[ 1699.284674] panic occurred, switching back to text console
Thanks for the detailed report!

I don't think that particular fix is kosher, since this basically
changes the address family ops of the parent listening socket ('sk'
here).The parent listening socket needs to keep its IPv6 af_ops so its
IPv6 children can get the right af_ops.
Indeed, my approach breaks ipv6 after first mapped connection.
We should probably either: (a) make sure the af_ops of the child
socket are set correctly earlier, or (b) not use dynamic dispatch
through the af_ops within tcp_create_openreq_child(), and just do the
sk_rx_dst_set a tiny bit later. I've sent out a patch for approach (b)
here, since it's simpler:

  http://patchwork.ozlabs.org/patch/178525/

I've verified that IPv4, IPv6, and IPv4-mapped-IPv6 connections work
for me with this patch. But if you could test it as well, that would
be great.
I've tested it and can confirm that all three connection types work.
Thank you for the patch and explanation.

-- 
Kind regards,
Artem

Re: [PATCH] net: tcp: ipv6_mapped needs sk_rx_dst_set method

From: Eric Dumazet <hidden>
Date: 2012-08-19 10:48:45

On Sat, 2012-08-18 at 17:06 +0400, Artem Savkov wrote:
It doesn't seem to fix the problem with mapped ipv6 completely.
I'm still hitting a NULL pointer dereference with mapped ipv6:
Thanks Artem for the report, I see Neal took care of the problem.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help