Thread (10 messages) flat view 10 messages, 5 authors, 2012-08-19

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 ↗ jump to 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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help