commit a98426a
Michael Forney
·
2019-07-11 05:51:55 +0000 UTC
parent 63d8812
launch: Use iovec to avoid undefined behavior and VLAs with open device request
4 files changed,
+61,
-56
+24,
-16
1@@ -29,6 +29,7 @@
2
3 #include <errno.h>
4 #include <fcntl.h>
5+#include <limits.h>
6 #include <poll.h>
7 #include <spawn.h>
8 #include <stdbool.h>
9@@ -172,30 +173,37 @@ handle_signal(int sig)
10 static void
11 handle_socket_data(int socket)
12 {
13- char buffer[BUFSIZ];
14- struct swc_launch_request *request = (void *)&buffer;
15+ struct swc_launch_request request;
16 struct swc_launch_event response;
17+ char path[PATH_MAX];
18+ struct iovec request_iov[2] = {
19+ {.iov_base = &request, .iov_len = sizeof(request)},
20+ {.iov_base = path, .iov_len = sizeof(path)},
21+ };
22+ struct iovec response_iov[1] = {
23+ {.iov_base = &response, .iov_len = sizeof(response)},
24+ };
25 int fd = -1;
26 struct stat st;
27 ssize_t size;
28
29- size = receive_fd(socket, &fd, buffer, sizeof(buffer));
30-
31- if (size == -1 || size == 0)
32+ size = receive_fd(socket, &fd, request_iov, 2);
33+ if (size == -1 || size == 0 || size < sizeof(request))
34 return;
35+ size -= sizeof(request);
36
37 response.type = SWC_LAUNCH_EVENT_RESPONSE;
38- response.serial = request->serial;
39+ response.serial = request.serial;
40
41- switch (request->type) {
42+ switch (request.type) {
43 case SWC_LAUNCH_REQUEST_OPEN_DEVICE:
44- if (buffer[size - 1] != '\0') {
45+ if (size == 0 || path[size - 1] != '\0') {
46 fprintf(stderr, "path is not NULL terminated\n");
47 goto fail;
48 }
49
50- if (stat(request->path, &st) == -1) {
51- fprintf(stderr, "stat %s: %s\n", request->path, strerror(errno));
52+ if (stat(path, &st) == -1) {
53+ fprintf(stderr, "stat %s: %s\n", path, strerror(errno));
54 goto fail;
55 }
56
57@@ -219,10 +227,10 @@ handle_socket_data(int socket)
58 goto fail;
59 }
60
61- fd = open(request->path, request->flags);
62+ fd = open(path, request.flags);
63
64 if (fd == -1) {
65- fprintf(stderr, "open %s: %s\n", request->path, strerror(errno));
66+ fprintf(stderr, "open %s: %s\n", path, strerror(errno));
67 goto fail;
68 }
69
70@@ -240,11 +248,11 @@ handle_socket_data(int socket)
71 if (!active)
72 goto fail;
73
74- if (ioctl(tty_fd, VT_ACTIVATE, request->vt) == -1)
75- fprintf(stderr, "failed to activate VT %d: %s\n", request->vt, strerror(errno));
76+ if (ioctl(tty_fd, VT_ACTIVATE, request.vt) == -1)
77+ fprintf(stderr, "failed to activate VT %d: %s\n", request.vt, strerror(errno));
78 break;
79 default:
80- fprintf(stderr, "unknown request %u\n", request->type);
81+ fprintf(stderr, "unknown request %u\n", request.type);
82 goto fail;
83 }
84
85@@ -255,7 +263,7 @@ fail:
86 response.success = false;
87 fd = -1;
88 done:
89- send_fd(socket, fd, &response, sizeof(response));
90+ send_fd(socket, fd, response_iov, 1);
91 }
92
93 static void
+13,
-25
1@@ -5,18 +5,14 @@
2 #include <string.h>
3
4 ssize_t
5-send_fd(int socket, int fd, const void *buffer, size_t buffer_size)
6+send_fd(int socket, int fd, struct iovec *iov, int iovlen)
7 {
8 char control[CMSG_SPACE(sizeof(fd))];
9- struct iovec iov = {
10- .iov_base = (void *)buffer,
11- .iov_len = buffer_size,
12- };
13 struct msghdr message = {
14 .msg_name = NULL,
15 .msg_namelen = 0,
16- .msg_iov = &iov,
17- .msg_iovlen = 1,
18+ .msg_iov = iov,
19+ .msg_iovlen = iovlen,
20 };
21 struct cmsghdr *cmsg;
22
23@@ -39,39 +35,31 @@ send_fd(int socket, int fd, const void *buffer, size_t buffer_size)
24 }
25
26 ssize_t
27-receive_fd(int socket, int *fd, void *buffer, size_t buffer_size)
28+receive_fd(int socket, int *fd, struct iovec *iov, int iovlen)
29 {
30- if (!fd)
31- return recv(socket, buffer, buffer_size, 0);
32-
33 ssize_t size;
34 char control[CMSG_SPACE(sizeof(*fd))];
35- struct iovec iov = {
36- .iov_base = buffer,
37- .iov_len = buffer_size,
38- };
39 struct msghdr message = {
40 .msg_name = NULL,
41 .msg_namelen = 0,
42- .msg_iov = &iov,
43- .msg_iovlen = 1,
44- .msg_control = &control,
45- .msg_controllen = sizeof(control),
46+ .msg_iov = iov,
47+ .msg_iovlen = iovlen,
48 };
49 struct cmsghdr *cmsg;
50
51- *fd = -1;
52+ if (fd) {
53+ *fd = -1;
54+ message.msg_control = &control;
55+ message.msg_controllen = sizeof(control);
56+ }
57+
58 size = recvmsg(socket, &message, 0);
59 if (size < 0)
60 return -1;
61
62 cmsg = CMSG_FIRSTHDR(&message);
63-
64- if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(*fd)) &&
65- cmsg->cmsg_level == SOL_SOCKET &&
66- cmsg->cmsg_type == SCM_RIGHTS) {
67+ if (fd && cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(*fd)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
68 memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
69- }
70
71 return size;
72 }
+4,
-3
1@@ -30,6 +30,8 @@
2
3 #define SWC_LAUNCH_SOCKET_ENV "SWC_LAUNCH_SOCKET"
4
5+struct iovec;
6+
7 struct swc_launch_request {
8 enum {
9 SWC_LAUNCH_REQUEST_OPEN_DEVICE,
10@@ -41,7 +43,6 @@ struct swc_launch_request {
11 union {
12 struct /* OPEN_DEVICE */ {
13 int flags;
14- char path[];
15 };
16 struct /* ACTIVATE_VT */ {
17 unsigned vt;
18@@ -64,7 +65,7 @@ struct swc_launch_event {
19 };
20 };
21
22-ssize_t send_fd(int socket, int fd, const void *buffer, size_t buffer_size);
23-ssize_t receive_fd(int socket, int *fd, void *buffer, size_t buffer_size);
24+ssize_t send_fd(int socket, int fd, struct iovec *iov, int iovlen);
25+ssize_t receive_fd(int socket, int *fd, struct iovec *iov, int iovlen);
26
27 #endif
+20,
-12
1@@ -58,8 +58,11 @@ static int
2 handle_data(int fd, uint32_t mask, void *data)
3 {
4 struct swc_launch_event event;
5+ struct iovec iov[1] = {
6+ {.iov_base = &event, .iov_len = sizeof(event)},
7+ };
8
9- if (receive_fd(fd, NULL, &event, sizeof(event)) != -1)
10+ if (receive_fd(fd, NULL, iov, 1) != -1)
11 handle_event(&event);
12 return 1;
13 }
14@@ -95,14 +98,22 @@ launch_finalize(void)
15 }
16
17 static bool
18-send_request(struct swc_launch_request *request, size_t size, struct swc_launch_event *event, int out_fd, int *in_fd)
19+send_request(struct swc_launch_request *request, const void *data, size_t size, struct swc_launch_event *event, int out_fd, int *in_fd)
20 {
21+ struct iovec request_iov[2] = {
22+ {.iov_base = request, .iov_len = sizeof(*request)},
23+ {.iov_base = (void *)data, .iov_len = size},
24+ };
25+ struct iovec response_iov[1] = {
26+ {.iov_base = event, .iov_len = sizeof(*event)},
27+ };
28+
29 request->serial = ++launch.next_serial;
30
31- if (send_fd(launch.socket, out_fd, request, size) == -1)
32+ if (send_fd(launch.socket, out_fd, request_iov, 1 + (size > 0)) == -1)
33 return false;
34
35- while (receive_fd(launch.socket, in_fd, event, sizeof(*event)) != -1) {
36+ while (receive_fd(launch.socket, in_fd, response_iov, 1) != -1) {
37 if (event->type == SWC_LAUNCH_EVENT_RESPONSE && event->serial == request->serial)
38 return true;
39 handle_event(event);
40@@ -114,17 +125,14 @@ send_request(struct swc_launch_request *request, size_t size, struct swc_launch_
41 int
42 launch_open_device(const char *path, int flags)
43 {
44- size_t path_size = strlen(path);
45- char buffer[sizeof(struct swc_launch_request) + path_size + 1];
46- struct swc_launch_request *request = (void *)buffer;
47+ struct swc_launch_request request;
48 struct swc_launch_event response;
49 int fd;
50
51- request->type = SWC_LAUNCH_REQUEST_OPEN_DEVICE;
52- request->flags = flags;
53- strcpy(request->path, path);
54+ request.type = SWC_LAUNCH_REQUEST_OPEN_DEVICE;
55+ request.flags = flags;
56
57- if (!send_request(request, sizeof(buffer), &response, -1, &fd))
58+ if (!send_request(&request, path, strlen(path) + 1, &response, -1, &fd))
59 return -1;
60
61 return fd;
62@@ -139,7 +147,7 @@ launch_activate_vt(unsigned vt)
63 request.type = SWC_LAUNCH_REQUEST_ACTIVATE_VT;
64 request.vt = vt;
65
66- if (!send_request(&request, sizeof(request), &response, -1, NULL))
67+ if (!send_request(&request, NULL, 0, &response, -1, NULL))
68 return false;
69
70 return response.success;