diff options
author | Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com> | 2012-03-09 12:51:42 +0200 |
---|---|---|
committer | Kristian Høgsberg <krh@bitplanet.net> | 2012-03-10 16:01:46 -0500 |
commit | 73d4a53672c66fb2ad9576545a5aae3bad2483ed (patch) | |
tree | 9bbe3d01dc32f1b3f59c567a832f750a8ab1243e | |
parent | 46df9232faa5f2e154ad14b6b10ca2475dbbf83b (diff) |
The buffer used by wl_connection_data to receive a cmsg is 128 bytes
long. This can hold at most 28 fds but when a cmsg is generated for
sending the fds, there is no check for this limitation. The man page
for recvmsg does not show any way of recovering from MSG_CTRUNC, that
happens when the buffer supplied for cmsg is too short.
Fix this by flushing the data to be written instead of generating a
cmsg buffer longer than the maximum.
-rw-r--r-- | src/connection.c | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/src/connection.c b/src/connection.c index 1ea2418..fa01545 100644 --- a/src/connection.c +++ b/src/connection.c @@ -56,9 +56,13 @@ struct wl_closure { uint32_t *start; }; +#define MAX_FDS_OUT 28 +#define CLEN (CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t))) + struct wl_connection { struct wl_buffer in, out; struct wl_buffer fds_in, fds_out; + int n_fds_out; int fd; void *data; wl_connection_update_func_t update; @@ -217,7 +221,7 @@ build_cmsg(struct wl_buffer *buffer, char *data, int *clen) static void close_fds(struct wl_buffer *buffer) { - int fds[32], i, count; + int fds[MAX_FDS_OUT], i, count; size_t size; size = buffer->head - buffer->tail; @@ -252,7 +256,7 @@ wl_connection_data(struct wl_connection *connection, uint32_t mask) { struct iovec iov[2]; struct msghdr msg; - char cmsg[128]; + char cmsg[CLEN]; int len, count, clen; if (mask & WL_CONNECTION_WRITABLE) { @@ -389,6 +393,21 @@ wl_message_size_extra(const struct wl_message *message) return extra; } +static int +wl_connection_put_fd(struct wl_connection *connection, int32_t fd) +{ + if (connection->n_fds_out + 1 > MAX_FDS_OUT) { + if (wl_connection_data(connection, WL_CONNECTION_WRITABLE)) + return -1; + connection->n_fds_out = 0; + } + + wl_buffer_put(&connection->fds_out, &fd, sizeof fd); + connection->n_fds_out++; + + return 0; +} + struct wl_closure * wl_connection_vmarshal(struct wl_connection *connection, struct wl_object *sender, @@ -510,8 +529,11 @@ wl_connection_vmarshal(struct wl_connection *connection, abort(); } *fd_ptr = dup_fd; - wl_buffer_put(&connection->fds_out, - &dup_fd, sizeof dup_fd); + if (wl_connection_put_fd(connection, dup_fd)) { + printf("request could not be mashaled: " + "can't send file descriptor"); + return NULL; + } break; default: fprintf(stderr, "unhandled format code: '%c'\n", |