UDS: sendmsg/recvmsg fixes

- 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
This commit is contained in:
David van Moolenbroek 2013-10-04 21:10:01 +02:00 committed by Lionel Sambuc
parent f3d8aa65ac
commit 9e3e032c26

View File

@ -629,7 +629,7 @@ do_recvfrom(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant)
static int static int
msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data, 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; int i, rc, nfds, totalfds;
struct msghdr msghdr; 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; return OK;
} }
static int 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; int rc, i, j;
dprintf(("UDS: send_fds(%d)\n", minor)); dprintf(("UDS: send_fds(%d)\n", minor));
/* Verify the file descriptors and get their filps. */ /* 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, if ((rc = vfs_verify_fd(uds_fd_table[minor].owner,
data->fds[i], &data->filps[i])) != OK) data->fds[i], &data->filps[i])) != OK)
return rc; return rc;
} }
/* Set them as in-flight. */ /* 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) { 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 */ vfs_put_filp(data->filps[j]); /* revert */
return rc; return rc;
} }
} }
data->nfiledes = new_total;
return OK; return OK;
} }
@ -805,7 +807,7 @@ recv_cred(devminor_t minor, struct ancillary *data,
static int static int
do_sendmsg(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) 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; struct msg_control msg_ctrl;
dprintf(("UDS: do_sendmsg(%d)\n", minor)); 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. * ones.
*/ */
if ((rc = msg_control_read(&msg_ctrl, 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 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 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); clen_avail = MIN(msg_ctrl.msg_controllen, MSG_CONTROL_MAX);
if (uds_fd_table[minor].ancillary_data.nfiledes > 0) { 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); uds_fd_table[minor].ancillary_data.nfiledes);
} }
/* if there is room we also include credentials */ /* 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) if (clen_needed > clen_avail)
return EOVERFLOW; return EOVERFLOW;
rc = recv_fds(minor, &uds_fd_table[minor].ancillary_data, &msg_ctrl); if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
if (rc != OK) if ((rc = recv_fds(minor, &uds_fd_table[minor].ancillary_data,
&msg_ctrl)) != OK)
return rc; return rc;
}
if (clen_desired <= clen_avail) { if (clen_desired <= clen_avail) {
rc = recv_cred(minor, &uds_fd_table[minor].ancillary_data, rc = recv_cred(minor, &uds_fd_table[minor].ancillary_data,
&msg_ctrl); &msg_ctrl);
if (rc != OK) if (rc != OK)
return rc; return rc;
} msg_ctrl.msg_controllen = clen_desired;
} else
msg_ctrl.msg_controllen = clen_needed;
/* Send the control data to the user. */ /* Send the control data to the user. */
return sys_safecopyto(endpt, grant, 0, (vir_bytes) &msg_ctrl, return sys_safecopyto(endpt, grant, 0, (vir_bytes) &msg_ctrl,