aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@openvz.org>2008-03-21 18:52:00 -0400
committerDavid S. Miller <davem@davemloft.net>2008-03-21 18:52:00 -0400
commit28518fc1701a757a3df8aa2d2ac2e5d1efd1c3e5 (patch)
treefde53a9cca0abc6c9f7a5f67656d65c385c0ec8b
parentb1153f29ee07dc1a788964409255a4b4fae50b98 (diff)
[NET]: NULL pointer dereference and other nasty things in /proc/net/(tcp|udp)[6]
Commits f40c81 ([NETNS][IPV4] tcp - make proc handle the network namespaces) and a91275 ([NETNS][IPV6] udp - make proc handle the network namespace) both introduced bad checks on sockets and tw buckets to belong to proper net namespace. I.e. when checking for socket to belong to given net and family the do { sk = sk_next(sk); } while (sk && sk->sk_net != net && sk->sk_family != family); constructions were used. This is wrong, since as soon as the sk->sk_net fits the net the socket is immediately returned, even if it belongs to other family. As the result four /proc/net/(udp|tcp)[6] entries show wrong info. The udp6 entry even oopses when dereferencing inet6_sk(sk) pointer: static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) { ... struct ipv6_pinfo *np = inet6_sk(sp); ... dest = &np->daddr; /* will be NULL for AF_INET sockets */ ... seq_printf(... dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], ... Fix it by converting && to ||. Signed-off-by: Pavel Emelyanov <xemul@openvz.org> Acked-by: Daniel Lezcano <dlezcano@fr.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/tcp_ipv4.c4
-rw-r--r--net/ipv4/udp.c2
2 files changed, 3 insertions, 3 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 744bc9d6cebc..0ba6e911c979 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2050,7 +2050,7 @@ static void *established_get_first(struct seq_file *seq)
2050 st->state = TCP_SEQ_STATE_TIME_WAIT; 2050 st->state = TCP_SEQ_STATE_TIME_WAIT;
2051 inet_twsk_for_each(tw, node, 2051 inet_twsk_for_each(tw, node,
2052 &tcp_hashinfo.ehash[st->bucket].twchain) { 2052 &tcp_hashinfo.ehash[st->bucket].twchain) {
2053 if (tw->tw_family != st->family && 2053 if (tw->tw_family != st->family ||
2054 tw->tw_net != net) { 2054 tw->tw_net != net) {
2055 continue; 2055 continue;
2056 } 2056 }
@@ -2078,7 +2078,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
2078 tw = cur; 2078 tw = cur;
2079 tw = tw_next(tw); 2079 tw = tw_next(tw);
2080get_tw: 2080get_tw:
2081 while (tw && tw->tw_family != st->family && tw->tw_net != net) { 2081 while (tw && (tw->tw_family != st->family || tw->tw_net != net)) {
2082 tw = tw_next(tw); 2082 tw = tw_next(tw);
2083 } 2083 }
2084 if (tw) { 2084 if (tw) {
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index a98c43c0a89c..fa946829d1e8 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1537,7 +1537,7 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk)
1537 sk = sk_next(sk); 1537 sk = sk_next(sk);
1538try_again: 1538try_again:
1539 ; 1539 ;
1540 } while (sk && sk->sk_net != net && sk->sk_family != state->family); 1540 } while (sk && (sk->sk_net != net || sk->sk_family != state->family));
1541 1541
1542 if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { 1542 if (!sk && ++state->bucket < UDP_HTABLE_SIZE) {
1543 sk = sk_head(state->hashtable + state->bucket); 1543 sk = sk_head(state->hashtable + state->bucket);