xorl %eax, %eax

sgi-xpc NULL pointer dereference

leave a comment »

This is another cute bug patched on Linux kernel 2.6.28.3. It was discovered by Robin Holt of SGI on 21 January 2009. It affects previous kernel releases that support XPC (Cross Partition Communication) operations. Of course, this is SGI specific so no need to worry if you don’t have an SGI lying around. The buggy function can be found under drivers/misc/sgi-xp/xpc_sn2.c at function xpc_get_deliverable_payload_sn2(). This routine is being used to retrieve the next message’s payload to be delivered. Here is the latter function:

1929 static void * 
1930 xpc_get_deliverable_payload_sn2(struct xpc_channel *ch) 
1931 { 
1933   struct xpc_msg_sn2 *msg; 
1934   void *payload = NULL;
        ... 
1937  do { 
1938     if (ch->flags & XPC_C_DISCONNECTING) 
1939       break; 
1940 
1941     get = ch_sn2->w_local_GP.get; 
        ... 
1960    /* pull the message from the remote partition */ 
1961 
1962    msg = xpc_pull_remote_msg_sn2(ch, get);
        ... 
1968    payload = &msg->payload; 
1969    break; 
1970    } 
1971 
1972  } while (1); 
1973 
1974 return payload; 
1975 } 
1976 

So.. at line 1938 it immediately exits if the message flag for disconnecting is set. In any other case, it stores the .get to variable get and then calls xpc_pull_remote_msg_sn2() to pull the message from the remote partition as the comment says. However, a quick review of this routine reveals that it can return NULL on various situations. Here is a stripped version of it:

1864 static struct xpc_msg_sn2 * 
1865 xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) 
1866 {
        ... 
1876   if (mutex_lock_interruptible(&ch_sn2->msg_to_pull_mutex) != 0) { 
1877     /* we were interrupted by a signal */ 
1878     return NULL;
        ... 
1901   if (ret != xpSuccess) {
        ...  
1911     return NULL; 
1912   }
        ... 
1923 return msg; 
1924 } 

Consequently, if we interrupt the MUTEX with a signal or if the partition communication fails it returns NULL. Now if you go back to the first function, you’ll see that msg which could be NULL is directly accessed at line 1968. Actually, it is being dereferenced to point to NULL->payload. This is where the error occurs. The patch for this bug was simple:

             msg = xpc_pull_remote_msg_sn2(ch, get);
 
-            DBUG_ON(msg != NULL && msg->number != get);
-            DBUG_ON(msg != NULL && (msg->flags & XPC_M_SN2_DONE));
-            DBUG_ON(msg != NULL && !(msg->flags & XPC_M_SN2_READY));
+            if (msg != NULL) {
+                DBUG_ON(msg->number != get);
+                DBUG_ON(msg->flags & XPC_M_SN2_DONE);
+                DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
 
-            payload = &msg->payload;
+                payload = &msg->payload;
+            }
             break;
         }

This way, only when the msg is not NULL the assignment will take place. I haven’t performed a detailed code review to conclude if this can be an exploitable NULL pointer dereference or not. However, it is obvious that it won’t be an easy to trigger one.. It might not even classified as a security bug. I’d be really happy if anyone who had tested this or performed a more detailed review would like to discuss it :)

Written by xorl

February 12, 2009 at 15:42

Posted in bugs, linux

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