swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

commit a98426ae69b43396cb22bb62316e270fb1f9d8f1
parent 63d8812d7789bd89d426c57ffb62a2ba95a0abaf
Author: Michael Forney <mforney@mforney.org>
Date:   Wed, 10 Jul 2019 22:51:55 -0700

launch: Use iovec to avoid undefined behavior and VLAs with open device request

Diffstat:
Mlaunch/launch.c | 40++++++++++++++++++++++++----------------
Mlaunch/protocol.c | 38+++++++++++++-------------------------
Mlaunch/protocol.h | 7++++---
Mlibswc/launch.c | 32++++++++++++++++++++------------
4 files changed, 61 insertions(+), 56 deletions(-)

diff --git a/launch/launch.c b/launch/launch.c @@ -29,6 +29,7 @@ #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <poll.h> #include <spawn.h> #include <stdbool.h> @@ -172,30 +173,37 @@ handle_signal(int sig) static void handle_socket_data(int socket) { - char buffer[BUFSIZ]; - struct swc_launch_request *request = (void *)&buffer; + struct swc_launch_request request; struct swc_launch_event response; + char path[PATH_MAX]; + struct iovec request_iov[2] = { + {.iov_base = &request, .iov_len = sizeof(request)}, + {.iov_base = path, .iov_len = sizeof(path)}, + }; + struct iovec response_iov[1] = { + {.iov_base = &response, .iov_len = sizeof(response)}, + }; int fd = -1; struct stat st; ssize_t size; - size = receive_fd(socket, &fd, buffer, sizeof(buffer)); - - if (size == -1 || size == 0) + size = receive_fd(socket, &fd, request_iov, 2); + if (size == -1 || size == 0 || size < sizeof(request)) return; + size -= sizeof(request); response.type = SWC_LAUNCH_EVENT_RESPONSE; - response.serial = request->serial; + response.serial = request.serial; - switch (request->type) { + switch (request.type) { case SWC_LAUNCH_REQUEST_OPEN_DEVICE: - if (buffer[size - 1] != '\0') { + if (size == 0 || path[size - 1] != '\0') { fprintf(stderr, "path is not NULL terminated\n"); goto fail; } - if (stat(request->path, &st) == -1) { - fprintf(stderr, "stat %s: %s\n", request->path, strerror(errno)); + if (stat(path, &st) == -1) { + fprintf(stderr, "stat %s: %s\n", path, strerror(errno)); goto fail; } @@ -219,10 +227,10 @@ handle_socket_data(int socket) goto fail; } - fd = open(request->path, request->flags); + fd = open(path, request.flags); if (fd == -1) { - fprintf(stderr, "open %s: %s\n", request->path, strerror(errno)); + fprintf(stderr, "open %s: %s\n", path, strerror(errno)); goto fail; } @@ -240,11 +248,11 @@ handle_socket_data(int socket) if (!active) goto fail; - if (ioctl(tty_fd, VT_ACTIVATE, request->vt) == -1) - fprintf(stderr, "failed to activate VT %d: %s\n", request->vt, strerror(errno)); + if (ioctl(tty_fd, VT_ACTIVATE, request.vt) == -1) + fprintf(stderr, "failed to activate VT %d: %s\n", request.vt, strerror(errno)); break; default: - fprintf(stderr, "unknown request %u\n", request->type); + fprintf(stderr, "unknown request %u\n", request.type); goto fail; } @@ -255,7 +263,7 @@ fail: response.success = false; fd = -1; done: - send_fd(socket, fd, &response, sizeof(response)); + send_fd(socket, fd, response_iov, 1); } static void diff --git a/launch/protocol.c b/launch/protocol.c @@ -5,18 +5,14 @@ #include <string.h> ssize_t -send_fd(int socket, int fd, const void *buffer, size_t buffer_size) +send_fd(int socket, int fd, struct iovec *iov, int iovlen) { char control[CMSG_SPACE(sizeof(fd))]; - struct iovec iov = { - .iov_base = (void *)buffer, - .iov_len = buffer_size, - }; struct msghdr message = { .msg_name = NULL, .msg_namelen = 0, - .msg_iov = &iov, - .msg_iovlen = 1, + .msg_iov = iov, + .msg_iovlen = iovlen, }; struct cmsghdr *cmsg; @@ -39,39 +35,31 @@ send_fd(int socket, int fd, const void *buffer, size_t buffer_size) } ssize_t -receive_fd(int socket, int *fd, void *buffer, size_t buffer_size) +receive_fd(int socket, int *fd, struct iovec *iov, int iovlen) { - if (!fd) - return recv(socket, buffer, buffer_size, 0); - ssize_t size; char control[CMSG_SPACE(sizeof(*fd))]; - struct iovec iov = { - .iov_base = buffer, - .iov_len = buffer_size, - }; struct msghdr message = { .msg_name = NULL, .msg_namelen = 0, - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = &control, - .msg_controllen = sizeof(control), + .msg_iov = iov, + .msg_iovlen = iovlen, }; struct cmsghdr *cmsg; - *fd = -1; + if (fd) { + *fd = -1; + message.msg_control = &control; + message.msg_controllen = sizeof(control); + } + size = recvmsg(socket, &message, 0); if (size < 0) return -1; cmsg = CMSG_FIRSTHDR(&message); - - if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(*fd)) && - cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { + if (fd && cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(*fd)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd)); - } return size; } diff --git a/launch/protocol.h b/launch/protocol.h @@ -30,6 +30,8 @@ #define SWC_LAUNCH_SOCKET_ENV "SWC_LAUNCH_SOCKET" +struct iovec; + struct swc_launch_request { enum { SWC_LAUNCH_REQUEST_OPEN_DEVICE, @@ -41,7 +43,6 @@ struct swc_launch_request { union { struct /* OPEN_DEVICE */ { int flags; - char path[]; }; struct /* ACTIVATE_VT */ { unsigned vt; @@ -64,7 +65,7 @@ struct swc_launch_event { }; }; -ssize_t send_fd(int socket, int fd, const void *buffer, size_t buffer_size); -ssize_t receive_fd(int socket, int *fd, void *buffer, size_t buffer_size); +ssize_t send_fd(int socket, int fd, struct iovec *iov, int iovlen); +ssize_t receive_fd(int socket, int *fd, struct iovec *iov, int iovlen); #endif diff --git a/libswc/launch.c b/libswc/launch.c @@ -58,8 +58,11 @@ static int handle_data(int fd, uint32_t mask, void *data) { struct swc_launch_event event; + struct iovec iov[1] = { + {.iov_base = &event, .iov_len = sizeof(event)}, + }; - if (receive_fd(fd, NULL, &event, sizeof(event)) != -1) + if (receive_fd(fd, NULL, iov, 1) != -1) handle_event(&event); return 1; } @@ -95,14 +98,22 @@ launch_finalize(void) } static bool -send_request(struct swc_launch_request *request, size_t size, struct swc_launch_event *event, int out_fd, int *in_fd) +send_request(struct swc_launch_request *request, const void *data, size_t size, struct swc_launch_event *event, int out_fd, int *in_fd) { + struct iovec request_iov[2] = { + {.iov_base = request, .iov_len = sizeof(*request)}, + {.iov_base = (void *)data, .iov_len = size}, + }; + struct iovec response_iov[1] = { + {.iov_base = event, .iov_len = sizeof(*event)}, + }; + request->serial = ++launch.next_serial; - if (send_fd(launch.socket, out_fd, request, size) == -1) + if (send_fd(launch.socket, out_fd, request_iov, 1 + (size > 0)) == -1) return false; - while (receive_fd(launch.socket, in_fd, event, sizeof(*event)) != -1) { + while (receive_fd(launch.socket, in_fd, response_iov, 1) != -1) { if (event->type == SWC_LAUNCH_EVENT_RESPONSE && event->serial == request->serial) return true; handle_event(event); @@ -114,17 +125,14 @@ send_request(struct swc_launch_request *request, size_t size, struct swc_launch_ int launch_open_device(const char *path, int flags) { - size_t path_size = strlen(path); - char buffer[sizeof(struct swc_launch_request) + path_size + 1]; - struct swc_launch_request *request = (void *)buffer; + struct swc_launch_request request; struct swc_launch_event response; int fd; - request->type = SWC_LAUNCH_REQUEST_OPEN_DEVICE; - request->flags = flags; - strcpy(request->path, path); + request.type = SWC_LAUNCH_REQUEST_OPEN_DEVICE; + request.flags = flags; - if (!send_request(request, sizeof(buffer), &response, -1, &fd)) + if (!send_request(&request, path, strlen(path) + 1, &response, -1, &fd)) return -1; return fd; @@ -139,7 +147,7 @@ launch_activate_vt(unsigned vt) request.type = SWC_LAUNCH_REQUEST_ACTIVATE_VT; request.vt = vt; - if (!send_request(&request, sizeof(request), &response, -1, NULL)) + if (!send_request(&request, NULL, 0, &response, -1, NULL)) return false; return response.success;