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;