1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

s3:unix_msg: don't fill cmsg buffer in unix_dgram_send_job()

Do this in queue_msg, instead.
This renders unix_dgram_send_job() as simple as it was before
we introduced fd-passing -- as it is intended.

This also changes struct unix_dgram_msg to not contain
the fd-array, but the correspondingly filled msghdr and cmsg buf.

Pair-Programmed-With: Volker Lendecke <vl@samba.org>
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Michael Adam <obnox@samba.org>
Signed-off-by: Volker Lendecke <vl@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
Michael Adam 2014-09-29 11:08:53 +02:00
parent b38ed7311a
commit d8af3e76a3

View File

@ -43,7 +43,7 @@ struct unix_dgram_msg {
ssize_t sent;
int sys_errno;
size_t num_fds;
int *fds;
struct msghdr msg;
struct iovec iov;
};
@ -443,7 +443,7 @@ static void unix_dgram_send_queue_free(struct unix_dgram_send_queue *q)
struct unix_dgram_msg *msg;
msg = q->msgs;
DLIST_REMOVE(q->msgs, msg);
close_fd_array(msg->fds, msg->num_fds);
close_fd_array_cmsg(&msg->msg);
free(msg);
}
close(q->sock);
@ -472,19 +472,35 @@ static int queue_msg(struct unix_dgram_send_queue *q,
ssize_t data_len;
uint8_t *data_buf;
size_t msglen;
size_t fds_size = sizeof(int) * num_fds;
int fds_copy[MIN(num_fds, INT8_MAX)];
size_t fds_padding = 0;
int i;
size_t tmp;
int ret = -1;
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
size_t fds_size = sizeof(int) * MIN(num_fds, INT8_MAX);
int fds_copy[MIN(num_fds, INT8_MAX)];
size_t cmsg_len = CMSG_LEN(fds_size);
size_t cmsg_space = CMSG_SPACE(fds_size);
char *cmsg_buf;
#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
if (num_fds > INT8_MAX) {
return EINVAL;
}
#ifndef HAVE_STRUCT_MSGHDR_MSG_CONTROL
if (num_fds > 0) {
return ENOSYS;
}
#endif
msglen = sizeof(struct unix_dgram_msg);
/*
* Note: No need to check for overflow here,
* since cmsg will store <= INT8_MAX fds.
*/
msglen += cmsg_space;
data_len = iov_buflen(iov, iovlen);
if (data_len == -1) {
return EINVAL;
@ -497,27 +513,7 @@ static int queue_msg(struct unix_dgram_send_queue *q,
}
msglen = tmp;
if (num_fds > 0) {
const size_t fds_align = sizeof(int) - 1;
tmp = msglen + fds_align;
if ((tmp < msglen) || (tmp < fds_align)) {
/* overflow */
return EINVAL;
}
tmp &= ~fds_align;
fds_padding = tmp - msglen;
msglen = tmp;
tmp = msglen + fds_size;
if ((tmp < msglen) || (tmp < fds_size)) {
/* overflow */
return EINVAL;
}
msglen = tmp;
}
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
for (i = 0; i < num_fds; i++) {
fds_copy[i] = -1;
}
@ -529,6 +525,7 @@ static int queue_msg(struct unix_dgram_send_queue *q,
goto fail;
}
}
#endif
msg = malloc(msglen);
if (msg == NULL) {
@ -537,30 +534,55 @@ static int queue_msg(struct unix_dgram_send_queue *q,
}
msg->sock = q->sock;
msg->num_fds = num_fds;
data_buf = (uint8_t *)(msg + 1);
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
if (num_fds > 0) {
cmsg_buf = (char *)data_buf;
memset(cmsg_buf, 0, cmsg_space);
data_buf += cmsg_space;
} else {
cmsg_buf = NULL;
cmsg_space = 0;
}
#endif
msg->iov = (struct iovec) {
.iov_base = (void *)data_buf,
.iov_len = data_len,
};
msg->msg = (struct msghdr) {
.msg_iov = &msg->iov,
.msg_iovlen = 1,
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
.msg_control = cmsg_buf,
.msg_controllen = cmsg_space,
#endif
};
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
if (num_fds > 0) {
struct cmsghdr *cmsg;
void *fdptr;
cmsg = CMSG_FIRSTHDR(&msg->msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = cmsg_len;
fdptr = CMSG_DATA(cmsg);
memcpy(fdptr, fds_copy, fds_size);
msg->msg.msg_controllen = cmsg->cmsg_len;
}
#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
for (i=0; i<iovlen; i++) {
memcpy(data_buf, iov[i].iov_base, iov[i].iov_len);
data_buf += iov[i].iov_len;
}
msg->num_fds = num_fds;
if (msg->num_fds > 0) {
void *fds_ptr;
data_buf += fds_padding;
fds_ptr= (void *)data_buf;
memcpy(fds_ptr, fds_copy, fds_size);
msg->fds = (int *)fds_ptr;
} else {
msg->fds = NULL;
}
DLIST_ADD_END(q->msgs, msg, struct unix_dgram_msg);
return 0;
@ -572,36 +594,9 @@ fail:
static void unix_dgram_send_job(void *private_data)
{
struct unix_dgram_msg *dmsg = private_data;
struct msghdr msg = {
.msg_iov = &dmsg->iov,
.msg_iovlen = 1,
};
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
struct cmsghdr *cmsg;
size_t fds_size = sizeof(int) * dmsg->num_fds;
size_t cmsg_len = CMSG_LEN(fds_size);
size_t cmsg_space = CMSG_SPACE(fds_size);
char cmsg_buf[cmsg_space];
if (dmsg->num_fds > 0) {
void *fdptr;
memset(cmsg_buf, 0, cmsg_space);
msg.msg_control = cmsg_buf;
msg.msg_controllen = cmsg_space;
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = cmsg_len;
fdptr = CMSG_DATA(cmsg);
memcpy(fdptr, dmsg->fds, fds_size);
msg.msg_controllen = cmsg->cmsg_len;
}
#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
do {
dmsg->sent = sendmsg(dmsg->sock, &msg, 0);
dmsg->sent = sendmsg(dmsg->sock, &dmsg->msg, 0);
} while ((dmsg->sent == -1) && (errno == EINTR));
if (dmsg->sent == -1) {
@ -635,7 +630,7 @@ static void unix_dgram_job_finished(struct poll_watch *w, int fd, short events,
msg = q->msgs;
DLIST_REMOVE(q->msgs, msg);
close_fd_array(msg->fds, msg->num_fds);
close_fd_array_cmsg(&msg->msg);
free(msg);
if (q->msgs != NULL) {