gsocket: Work around broken CMSG_FIRSTHDR()
authorPHO <pho@cielonegro.org>
Mon, 17 Dec 2012 23:33:50 +0000 (08:33 +0900)
committerDan Winship <danw@gnome.org>
Tue, 18 Dec 2012 18:31:02 +0000 (13:31 -0500)
As RFC 2292 points out, some platforms (e.g. Darwin 9.8.0) provide
CMSG_FIRSTHDR(msg) which just returns msg.msg_control without first
checking if msg.msg_controllen is non-zero. We need a workaround for
such platforms not to let g_socket_receive_message() segfault.

https://bugzilla.gnome.org/show_bug.cgi?id=690388

gio/gsocket.c

index ebb831c..cb09dfc 100644 (file)
@@ -4154,33 +4154,36 @@ g_socket_receive_message (GSocket                 *socket,
       GPtrArray *my_messages = NULL;
       struct cmsghdr *cmsg;
 
-      for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg))
-       {
-         GSocketControlMessage *message;
-
-         message = g_socket_control_message_deserialize (cmsg->cmsg_level,
-                                                         cmsg->cmsg_type,
-                                                         cmsg->cmsg_len - ((char *)CMSG_DATA (cmsg) - (char *)cmsg),
-                                                         CMSG_DATA (cmsg));
-         if (message == NULL)
-           /* We've already spewed about the problem in the
-              deserialization code, so just continue */
-           continue;
-
-         if (messages == NULL)
-           {
-             /* we have to do it this way if the user ignores the
-              * messages so that we will close any received fds.
-              */
-             g_object_unref (message);
-           }
-         else
-           {
-             if (my_messages == NULL)
-               my_messages = g_ptr_array_new ();
-             g_ptr_array_add (my_messages, message);
-           }
-       }
+      if (msg.msg_controllen >= sizeof (struct cmsghdr))
+        {
+          for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg))
+            {
+              GSocketControlMessage *message;
+
+              message = g_socket_control_message_deserialize (cmsg->cmsg_level,
+                                                              cmsg->cmsg_type,
+                                                              cmsg->cmsg_len - ((char *)CMSG_DATA (cmsg) - (char *)cmsg),
+                                                              CMSG_DATA (cmsg));
+              if (message == NULL)
+                /* We've already spewed about the problem in the
+                   deserialization code, so just continue */
+                continue;
+
+              if (messages == NULL)
+                {
+                  /* we have to do it this way if the user ignores the
+                   * messages so that we will close any received fds.
+                   */
+                  g_object_unref (message);
+                }
+              else
+                {
+                  if (my_messages == NULL)
+                    my_messages = g_ptr_array_new ();
+                  g_ptr_array_add (my_messages, message);
+                }
+            }
+        }
 
       if (num_messages)
        *num_messages = my_messages != NULL ? my_messages->len : 0;