ipv6: do not clear pinet6 field

We have seen multiple NULL dereferences in __inet6_lookup_established()

After analysis, I found that inet6_sk() could be NULL while the
check for sk_family == AF_INET6 was true.

Bug was added in linux-2.6.29 when RCU lookups were introduced in UDP
and TCP stacks.

Once an IPv6 socket, using SLAB_DESTROY_BY_RCU is inserted in a hash
table, we no longer can clear pinet6 field.

This patch extends logic used in commit fcbdf09d96
("net: fix nulls list corruptions in sk_prot_alloc")

TCP/UDP/UDPLite IPv6 protocols provide their own .clear_sk() method
to make sure we do not clear pinet6 field.

At socket clone phase, we do not really care, as cloning the parent (non
NULL) pinet6 is not adding a fatal race.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet
2013-05-09 10:28:16 +00:00
committed by David S. Miller
parent 233c7df082
commit f77d602124
6 changed files with 39 additions and 14 deletions

View File

@@ -1890,6 +1890,17 @@ void tcp6_proc_exit(struct net *net)
}
#endif
static void tcp_v6_clear_sk(struct sock *sk, int size)
{
struct inet_sock *inet = inet_sk(sk);
/* we do not want to clear pinet6 field, because of RCU lookups */
sk_prot_clear_nulls(sk, offsetof(struct inet_sock, pinet6));
size -= offsetof(struct inet_sock, pinet6) + sizeof(inet->pinet6);
memset(&inet->pinet6 + 1, 0, size);
}
struct proto tcpv6_prot = {
.name = "TCPv6",
.owner = THIS_MODULE,
@@ -1933,6 +1944,7 @@ struct proto tcpv6_prot = {
#ifdef CONFIG_MEMCG_KMEM
.proto_cgroup = tcp_proto_cgroup,
#endif
.clear_sk = tcp_v6_clear_sk,
};
static const struct inet6_protocol tcpv6_protocol = {