]> Zhao Yanbai Git Server - minix.git/commitdiff
UDS: sendmsg/recvmsg fixes
authorDavid van Moolenbroek <david@minix3.org>
Fri, 4 Oct 2013 19:10:01 +0000 (21:10 +0200)
committerLionel Sambuc <lionel@minix3.org>
Sat, 1 Mar 2014 08:04:58 +0000 (09:04 +0100)
- sendmsg: the accumulation of multiple in-flight file descriptors was
  already described in the comments; now the code actually does what
  the comments say :) -- also, added robustness in case of a failure;
- recvmsg: only create a socket rights message if there are file
  descriptors pending at all;
- recvmsg: copy back the control message length;
- recvmsg: use CMSG_SPACE instead of CMSG_LEN to compute sizes.

Not sure if all of this is now working according to specification,
but at least tmux seems to be happy with it.

Change-Id: I8d076c14c3ff3220b7fea730e0f08f4b4254ede5

drivers/uds/ioc_uds.c

index b31bcd8775b3ce3c847412e7ebe118a4a75d9190..b9336fdfed35bc4a108bb50738e6262c0a5f9121 100644 (file)
@@ -629,7 +629,7 @@ do_recvfrom(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant)
 
 static int
 msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data,
-       devminor_t minor)
+       devminor_t minor, int *new_total)
 {
        int i, rc, nfds, totalfds;
        struct msghdr msghdr;
@@ -669,34 +669,36 @@ msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data,
                }
        }
 
-       data->nfiledes = totalfds;
+       *new_total = totalfds;
 
        return OK;
 }
 
 static int
-send_fds(devminor_t minor, struct ancillary *data)
+send_fds(devminor_t minor, struct ancillary *data, int new_total)
 {
        int rc, i, j;
 
        dprintf(("UDS: send_fds(%d)\n", minor));
 
        /* Verify the file descriptors and get their filps. */
-       for (i = 0; i < data->nfiledes; i++) {
+       for (i = data->nfiledes; i < new_total; i++) {
                if ((rc = vfs_verify_fd(uds_fd_table[minor].owner,
                    data->fds[i], &data->filps[i])) != OK)
                        return rc;
        }
 
        /* Set them as in-flight. */
-       for (i = 0; i < data->nfiledes; i++) {
+       for (i = data->nfiledes; i < new_total; i++) {
                if ((rc = vfs_set_filp(data->filps[i])) != OK) {
-                       for (j = i - 1; j >= 0; j--)
+                       for (j = i - 1; j >= data->nfiledes; j--)
                                vfs_put_filp(data->filps[j]);   /* revert */
                        return rc;
                }
        }
 
+       data->nfiledes = new_total;
+
        return OK;
 }
 
@@ -805,7 +807,7 @@ recv_cred(devminor_t minor, struct ancillary *data,
 static int
 do_sendmsg(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant)
 {
-       int peer, rc, i;
+       int peer, rc, i, new_total;
        struct msg_control msg_ctrl;
 
        dprintf(("UDS: do_sendmsg(%d)\n", minor));
@@ -854,10 +856,10 @@ do_sendmsg(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant)
         * ones.
         */
        if ((rc = msg_control_read(&msg_ctrl,
-           &uds_fd_table[peer].ancillary_data, minor)) != OK)
+           &uds_fd_table[peer].ancillary_data, minor, &new_total)) != OK)
                return rc;
 
-       return send_fds(minor, &uds_fd_table[peer].ancillary_data);
+       return send_fds(minor, &uds_fd_table[peer].ancillary_data, new_total);
 }
 
 static int
@@ -888,26 +890,30 @@ do_recvmsg(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant)
        clen_avail = MIN(msg_ctrl.msg_controllen, MSG_CONTROL_MAX);
 
        if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
-               clen_needed = CMSG_LEN(sizeof(int) *
+               clen_needed = CMSG_SPACE(sizeof(int) *
                    uds_fd_table[minor].ancillary_data.nfiledes);
        }
 
        /* if there is room we also include credentials */
-       clen_desired = clen_needed + CMSG_LEN(sizeof(struct uucred));
+       clen_desired = clen_needed + CMSG_SPACE(sizeof(struct uucred));
 
        if (clen_needed > clen_avail)
                return EOVERFLOW;
 
-       rc = recv_fds(minor, &uds_fd_table[minor].ancillary_data, &msg_ctrl);
-       if (rc != OK)
-               return rc;
+       if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
+               if ((rc = recv_fds(minor, &uds_fd_table[minor].ancillary_data,
+                   &msg_ctrl)) != OK)
+                       return rc;
+       }
 
        if (clen_desired <= clen_avail) {
                rc = recv_cred(minor, &uds_fd_table[minor].ancillary_data,
                    &msg_ctrl);
                if (rc != OK)
                        return rc;
-       }
+               msg_ctrl.msg_controllen = clen_desired;
+       } else
+               msg_ctrl.msg_controllen = clen_needed;
 
        /* Send the control data to the user. */
        return sys_safecopyto(endpt, grant, 0, (vir_bytes) &msg_ctrl,