diff options
author | Eric Dumazet <edumazet@google.com> | 2013-05-09 10:28:16 +0000 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-05-19 11:38:38 -0700 |
commit | 285665993541f4f9d8bf80db6d7d27b205aa78b9 (patch) | |
tree | d389b0060c820630d09dee8ca19b7f91adcfe67c /net/core | |
parent | 766af4d9a4f5c36289f744a65898ce5bee643138 (diff) | |
download | lwn-285665993541f4f9d8bf80db6d7d27b205aa78b9.tar.gz lwn-285665993541f4f9d8bf80db6d7d27b205aa78b9.zip |
ipv6: do not clear pinet6 field
[ Upstream commit f77d602124d865c38705df7fa25c03de9c284ad2 ]
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 fcbdf09d9652c891
("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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/sock.c | 12 |
1 files changed, 0 insertions, 12 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index b261a7977746..1432266c4adf 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1209,18 +1209,6 @@ static void sock_copy(struct sock *nsk, const struct sock *osk) #endif } -/* - * caches using SLAB_DESTROY_BY_RCU should let .next pointer from nulls nodes - * un-modified. Special care is taken when initializing object to zero. - */ -static inline void sk_prot_clear_nulls(struct sock *sk, int size) -{ - if (offsetof(struct sock, sk_node.next) != 0) - memset(sk, 0, offsetof(struct sock, sk_node.next)); - memset(&sk->sk_node.pprev, 0, - size - offsetof(struct sock, sk_node.pprev)); -} - void sk_prot_clear_portaddr_nulls(struct sock *sk, int size) { unsigned long nulls1, nulls2; |