xorl %eax, %eax

OpenSolaris IP(7p) IPv6 Remote NULL Pointer Dereference

leave a comment »

I just saw this “new” vulnerability report. The bug was discovered and fixed by Sun Microsystems and it affects OpenSolaris based upon builds snv_106 through snv_124 on both SPARC and x86 platforms. Here is the vulnerable code path is through tcp_do_getsockname() which resides in common/inet/tcp/tcp.c.

static int
tcp_do_getsockname(tcp_t *tcp, struct sockaddr *sa, uint_t *salenp)
        sin_t *sin = (sin_t *)sa;
        sin6_t *sin6 = (sin6_t *)sa;

        switch (tcp->tcp_family) {
        case AF_INET6:
                if (*salenp < sizeof (sin6_t))
                        return (EINVAL);

                *sin6 = sin6_null;
                sin6->sin6_family = AF_INET6;
                if (tcp->tcp_state >= TCPS_BOUND) {
                        } else {
                                sin6->sin6_addr = tcp->tcp_ip6h->ip6_src;
                *salenp = sizeof (sin6_t);

        return (0);

This is the code that handles the ‘getsockname’ operation on TCP sockets. In case of an IPv6 socket it will initially check that its size is valid and then proceed with checking the state of the TCP connection. If this is less than ‘TCPS_BOUND’ which as we can read at common/inet/tcp.h is:

/* TCP states */
#define TCPS_CLOSED             -6
#define TCPS_IDLE               -5      /* idle (opened, but not bound) */
#define TCPS_BOUND              -4      /* bound, ready to connect or accept */
#define TCPS_LISTEN             -3      /* listening for connection */
#define TCPS_SYN_SENT           -2      /* active, have sent syn */
#define TCPS_SYN_RCVD           -1      /* have received syn (and sent ours) */
/* states < TCPS_ESTABLISHED are those where connections not established */
#define TCPS_ESTABLISHED        0       /* established */
#define TCPS_CLOSE_WAIT         1       /* rcvd fin, waiting for close */
/* states > TCPS_CLOSE_WAIT are those where user has closed */
#define TCPS_FIN_WAIT_1         2       /* have closed and sent fin */
#define TCPS_CLOSING            3       /* closed, xchd FIN, await FIN ACK */
#define TCPS_LAST_ACK           4       /* had fin and close; await FIN ACK */
/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
#define TCPS_FIN_WAIT_2         5       /* have closed, fin is acked */
#define TCPS_TIME_WAIT          6       /* in 2*msl quiet wait after close */

It will fall to the ‘else’ clause where it’ll attempt to initialize ‘sin6->sin6_addr’ with ‘tcp->tcp_ip6h->ip6_src’ which is the IPv6 source address of the TCP header. However, as James Carlson pointed out, the ‘tcp->tcp_ip6h’ pointer could be NULL and thus, this operation will result in NULL pointer dereference during that ‘else’ part.
A similar vulnerability was also present in the tcp_do_getpeername() routine which is located in the same source code file. For completeness, here is the definition of ‘tcp_ip6h’ pointer from ‘tcp_t’ data type as seen in common/inet/tcp.h header file.

 * Control structure for each open TCP stream,
 * defined only within the kernel or for a kmem user.
 * NOTE: tcp_reinit_values MUST have a line for each field in this structure!
#if (defined(_KERNEL) || defined(_KMEMUSER))
typedef struct tcp_s {
         ip6_t   *tcp_ip6h;              /* IPv6 header in the buffer */
#ifdef DEBUG
        pc_t                    tcmp_stk[15];
} tcp_t;

Written by xorl

December 6, 2009 at 04:56

Posted in bugs, solaris

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s