]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
[NET]: NULL pointer dereference and other nasty things in /proc/net/(tcp|udp)[6]
authorPavel Emelyanov <xemul@openvz.org>
Fri, 21 Mar 2008 22:52:00 +0000 (15:52 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 21 Mar 2008 22:52:00 +0000 (15:52 -0700)
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>
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c

index 744bc9d6cebc111c28e708ec536e6c068afa14c7..0ba6e911c9797efb4067c5628155814f5e14048b 100644 (file)
@@ -2050,7 +2050,7 @@ static void *established_get_first(struct seq_file *seq)
                st->state = TCP_SEQ_STATE_TIME_WAIT;
                inet_twsk_for_each(tw, node,
                                   &tcp_hashinfo.ehash[st->bucket].twchain) {
-                       if (tw->tw_family != st->family &&
+                       if (tw->tw_family != st->family ||
                            tw->tw_net != net) {
                                continue;
                        }
@@ -2078,7 +2078,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
                tw = cur;
                tw = tw_next(tw);
 get_tw:
-               while (tw && tw->tw_family != st->family && tw->tw_net != net) {
+               while (tw && (tw->tw_family != st->family || tw->tw_net != net)) {
                        tw = tw_next(tw);
                }
                if (tw) {
index a98c43c0a89cb7cb1bf3d8f9bc1a6a75f7d1c531..fa946829d1e850765fb4688b959e150ff4d079d2 100644 (file)
@@ -1537,7 +1537,7 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk)
                sk = sk_next(sk);
 try_again:
                ;
-       } while (sk && sk->sk_net != net && sk->sk_family != state->family);
+       } while (sk && (sk->sk_net != net || sk->sk_family != state->family));
 
        if (!sk && ++state->bucket < UDP_HTABLE_SIZE) {
                sk = sk_head(state->hashtable + state->bucket);