On Tue, 2013-05-21 at 15:44 +0400, Roman Gushchin wrote: > Hi, all! > > I think, it's good, but not enough. > > We still can't rely on the sk->sk_family field by dereferencing the > inet_sk(sk)->pinet6 field, because we can set the sk_family field to > the PF_INET6 value before setting pinet6 to an appropriate value > (assuming it is NULL just because it was not a PF_INET6 socket in a > previous life). > > net/ipv6/af_inet6.c: > static int inet6_create(struct net *net, struct socket *sock, int > protocol, int kern) > { > <...> > err = -ENOBUFS; > sk = sk_alloc(net, PF_INET6, GFP_KERNEL, answer_prot); > if (sk == NULL) > goto out; > <...> > sk->sk_destruct = inet_sock_destruct; > sk->sk_family = PF_INET6; > sk->sk_protocol = protocol; > > sk->sk_backlog_rcv = answer->prot->backlog_rcv; > > inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk); > <...> > } > > net/core/sock.c: > struct sock *sk_alloc(struct net *net, int family, gfp_t priority, > struct proto *prot) > { > struct sock *sk; > > sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family); > if (sk) { > sk->sk_family = family; > <...> > } > > > So, we need to care about setting sk_family to PF_INET6 _strictly_ after > setting the pinet6 field to a valid value (using rcu_assign_pointer(), > for instance). This can never happen. A socket cannot be find in a hash chain while pinet6 is not set. For a given socket pointer sk (say TCP or UDP), pinet6 is a constant and cannot change. (This is a property of SLAB_DESTROY_BY_RCU : slab cannot be merged, so all objects are of the same type) So the order of writing sk_family / pinet6 is irrelevant. Before inserting socket into tcp/udp hash table, all memory writes will have been committed. Only concern is when a socket is deleted/reused, and my patch address the problem. Thanks -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html