[PATCH 4/7] Add support for receiving fds in replies

Keith Packard keithp at keithp.com
Wed Nov 6 09:48:39 PST 2013


Mark Kettenis <mark.kettenis at xs4all.nl> writes:

> Same comment about not using the CMSG_ API properly.  Error handling
> of the recvmsg(2) call isn't adequate either.  Probably should
> consider MSG_TRUNC and MSG_CTRUNC as fatal errors and clean up any
> file descriptors that you did receive like we discussed for libxtrans.

MSG_TRUNC "can't happen", but MSG_CTRUNC would indicate an X server
error. Here's a patch that checks for both of them:

--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -882,6 +882,16 @@ int _xcb_in_read(xcb_connection_t *c)
     c->in.in_fd.ifd = 0;
     c->in.in_fd.nfd = 0;
     n = recvmsg(c->fd, &msg, 0);
+
+    /* Check for truncation errors. Only MSG_CTRUNC is
+     * probably possible here, which would indicate that
+     * the sender tried to transmit more than XCB_MAX_PASS_FD
+     * file descriptors.
+     */
+    if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
+        _xcb_conn_shutdown(c, XCB_CONN_ERROR);
+        return 0;
+    }

> I don't see a mechanism to "flush out" file descriptors that were
> received but not consumed, i.e. if a nasty server sent you some file
> descriptors together with a request for which you didn't expect any.
> Am I missing something?

You may have missed the abort at the top of _xcb_in_read where the
application will just exit if extra file descriptors are received.

How about this instead:

--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -878,9 +878,6 @@ int _xcb_in_read(xcb_connection_t *c)
         .msg_control = &c->in.in_fd,
         .msg_controllen = sizeof (struct cmsghdr) + sizeof (int) * XCB_MAX_PASS
     };
-    assert(c->in.in_fd.ifd == c->in.in_fd.nfd);
-    c->in.in_fd.ifd = 0;
-    c->in.in_fd.nfd = 0;
     n = recvmsg(c->fd, &msg, 0);
 
     /* Check for truncation errors. Only MSG_CTRUNC is
@@ -912,6 +909,22 @@ int _xcb_in_read(xcb_connection_t *c)
     }
     while(read_packet(c))
         /* empty */;
+#if HAVE_SENDMSG
+    c->in.in_fd.nfd -= c->in.in_fd.ifd;
+    c->in.in_fd.ifd = 0;
+
+    /* If we have any left-over file descriptors, then
+     * the server sent some that we weren't expecting.
+     * Close them and mark the connection as broken;
+     */
+    if (c->in.in_fd.nfd != 0) {
+        int i;
+        for (i = 0; i < c->in.in_fd.nfd; i++)
+            close(c->in.in_fd.fd[i]);
+        _xcb_conn_shutdown(c, XCB_CONN_ERROR);
+        return 0;
+    }
+#endif
 #ifndef _WIN32
     if((n > 0) || (n < 0 && errno == EAGAIN))
 #else

>> +    return nfd * sizeof (int);
>
> wouldn't it make more sense to simply return nfd here?

How about just making it a boolean function; that's all the caller cares
about:

--- a/src/xcb_in.c
+++ b/src/xcb_in.c
@@ -115,10 +115,10 @@ static int read_fds(xcb_connection_t *c, int *fds, int nfd
     int infd = c->in.in_fd.nfd - c->in.in_fd.ifd;
 
     if (nfd > infd)
-        return -1;
+        return 0;
     memcpy(fds, ifds, nfd * sizeof (int));
     c->in.in_fd.ifd += nfd;
-    return nfd * sizeof (int);
+    return 1;
 }
 #endif
 
@@ -279,7 +279,7 @@ static int read_packet(xcb_connection_t *c)
 #if HAVE_SENDMSG
     if (nfd)
     {
-        if (read_fds(c, (int *) &((char *) buf)[length], nfd) <= 0)
+        if (!read_fds(c, (int *) &((char *) buf)[length], nfd))
         {
             free(buf);
             return 0;

Thanks much for your review.

-- 
keith.packard at intel.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 827 bytes
Desc: not available
URL: <http://lists.x.org/archives/xorg-devel/attachments/20131106/53d1d50c/attachment-0001.pgp>


More information about the xorg-devel mailing list