1 /*
2  * Copyright © 2019 Manuel Stoeckl
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include "common.h"
27 #include "shadow.h"
28 
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/socket.h>
36 #include <time.h>
37 #include <unistd.h>
38 
shadow_sync(struct fd_translation_map * src_map,struct fd_translation_map * dst_map)39 static int shadow_sync(struct fd_translation_map *src_map,
40 		struct fd_translation_map *dst_map)
41 {
42 	struct transfer_queue queue;
43 	memset(&queue, 0, sizeof(queue));
44 	pthread_mutex_init(&queue.async_recv_queue.lock, NULL);
45 
46 	read_readable_pipes(src_map);
47 
48 	for (struct shadow_fd_link *lcur = src_map->link.l_next,
49 				   *lnxt = lcur->l_next;
50 			lcur != &src_map->link;
51 			lcur = lnxt, lnxt = lcur->l_next) {
52 		struct shadow_fd *sfd = (struct shadow_fd *)lcur;
53 		collect_update(NULL, sfd, &queue, false);
54 		/* collecting updates can reset `remote_can_X` state, so
55 		 * garbage collect the sfd */
56 		destroy_shadow_if_unreferenced(sfd);
57 	}
58 	for (int i = 0; i < queue.end; i++) {
59 		if (queue.vecs[i].iov_len < 8) {
60 			cleanup_transfer_queue(&queue);
61 			wp_error("Invalid message");
62 			return -1;
63 		}
64 		const uint32_t *header =
65 				(const uint32_t *)queue.vecs[i].iov_base;
66 		struct bytebuf msg;
67 		msg.data = queue.vecs[i].iov_base;
68 		msg.size = transfer_size(header[0]);
69 		if (apply_update(dst_map, NULL, NULL, transfer_type(header[0]),
70 				    (int32_t)header[1], &msg) == -1) {
71 			wp_error("Update failed");
72 			cleanup_transfer_queue(&queue);
73 			return -1;
74 		}
75 	}
76 	flush_writable_pipes(dst_map);
77 
78 	int nt = queue.end;
79 	cleanup_transfer_queue(&queue);
80 	return nt;
81 }
82 
create_pseudo_pipe(bool can_read,bool can_write,bool half_open_socket,int * spec_end,int * opp_end)83 static int create_pseudo_pipe(bool can_read, bool can_write,
84 		bool half_open_socket, int *spec_end, int *opp_end)
85 {
86 	bool pipe_possible = can_read != can_write;
87 	int pipe_fds[2];
88 	if (half_open_socket || !pipe_possible) {
89 		if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) == -1) {
90 			wp_error("Socketpair failed");
91 			return -1;
92 		}
93 		if (!can_read) {
94 			shutdown(pipe_fds[0], SHUT_RD);
95 		}
96 		if (!can_write) {
97 			shutdown(pipe_fds[0], SHUT_WR);
98 		}
99 	} else {
100 		if (pipe(pipe_fds) == -1) {
101 			wp_error("Pipe failed");
102 			return -1;
103 		}
104 		if (can_write) {
105 			int tmp = pipe_fds[0];
106 			pipe_fds[0] = pipe_fds[1];
107 			pipe_fds[1] = tmp;
108 		}
109 	}
110 	*spec_end = pipe_fds[0];
111 	*opp_end = pipe_fds[1];
112 	return 0;
113 }
114 
fd_is_readable(int fd)115 static char fd_is_readable(int fd)
116 {
117 	int flags = fcntl(fd, F_GETFL, 0);
118 	if (flags == -1) {
119 		wp_error("fctnl F_GETFL failed!");
120 		return '?';
121 	}
122 	flags = flags & O_ACCMODE;
123 	return (flags == O_RDONLY || flags == O_RDWR) ? 'R' : 'n';
124 }
125 
fd_is_writable(int fd)126 static char fd_is_writable(int fd)
127 {
128 	int flags = fcntl(fd, F_GETFL, 0);
129 	if (flags == -1) {
130 		wp_error("fctnl F_GETFL failed!");
131 		return '?';
132 	}
133 	flags = flags & O_ACCMODE;
134 	return (flags == O_WRONLY || flags == O_RDWR) ? 'W' : 'n';
135 }
136 
print_pipe_state(const char * desc,struct pipe_state * p)137 static void print_pipe_state(const char *desc, struct pipe_state *p)
138 {
139 	printf("%s state: %c %c %c %c%s\n", desc, p->can_read ? 'R' : 'n',
140 			p->can_write ? 'W' : 'n',
141 			p->remote_can_read ? 'R' : 'n',
142 			p->remote_can_write ? 'W' : 'n',
143 			p->pending_w_shutdown ? " shutdownWpending" : "");
144 }
145 
test_pipe_mirror(bool close_src,bool can_read,bool can_write,bool half_open_socket,bool interpret_as_force_iw)146 static bool test_pipe_mirror(bool close_src, bool can_read, bool can_write,
147 		bool half_open_socket, bool interpret_as_force_iw)
148 {
149 	if (can_read == can_write && half_open_socket) {
150 		return true;
151 	}
152 	printf("\nTesting:%s%s%s%s%s\n", can_read ? " read" : "",
153 			can_write ? " write" : "",
154 			half_open_socket ? " socket" : "",
155 			interpret_as_force_iw ? " force_iw" : "",
156 			close_src ? " close_src" : " close_dst");
157 	int spec_end, opp_end, anti_end = -1;
158 	if (create_pseudo_pipe(can_read, can_write, half_open_socket, &spec_end,
159 			    &opp_end) == -1) {
160 		return false;
161 	}
162 
163 	struct fd_translation_map src_map;
164 	setup_translation_map(&src_map, false);
165 
166 	struct fd_translation_map dst_map;
167 	setup_translation_map(&dst_map, true);
168 
169 	bool success = true;
170 
171 	/* Step 1: replicate */
172 	struct shadow_fd *src_shadow = translate_fd(&src_map, NULL, spec_end,
173 			FDC_PIPE, 0, NULL, false, interpret_as_force_iw);
174 	shadow_decref_transfer(src_shadow);
175 	int rid = src_shadow->remote_id;
176 	if (shadow_sync(&src_map, &dst_map) == -1) {
177 		success = false;
178 		goto cleanup;
179 	}
180 	struct shadow_fd *dst_shadow = get_shadow_for_rid(&dst_map, rid);
181 	if (!dst_shadow) {
182 		printf("Failed to create remote shadow structure\n");
183 		success = false;
184 		goto cleanup;
185 	}
186 	anti_end = dup(dst_shadow->fd_local);
187 	shadow_decref_transfer(dst_shadow);
188 
189 	if (set_nonblocking(anti_end) == -1 || set_nonblocking(opp_end) == -1) {
190 		printf("Failed to make user fds nonblocking\n");
191 		success = false;
192 		goto cleanup;
193 	}
194 	printf("spec %c %c %c %c | opp %c %c | anti %c %c\n",
195 			can_read ? 'R' : 'n', can_write ? 'W' : 'n',
196 			fd_is_readable(spec_end), fd_is_writable(spec_end),
197 			fd_is_readable(opp_end), fd_is_writable(opp_end),
198 			fd_is_readable(anti_end), fd_is_writable(anti_end));
199 
200 	print_pipe_state("dst", &dst_shadow->pipe);
201 	print_pipe_state("src", &src_shadow->pipe);
202 
203 	/* Step 2: transfer tests */
204 	for (int i = 0; i < 4; i++) {
205 		bool from_src = i % 2;
206 
207 		/* Smaller than a pipe buffer, so writing should always succeed
208 		 */
209 		char buf[4096];
210 		memset(buf, rand(), sizeof(buf));
211 
212 		int write_fd = from_src ? opp_end : anti_end;
213 		int read_fd = from_src ? anti_end : opp_end;
214 		const char *target = from_src ? "src" : "dst";
215 		const char *antitarget = from_src ? "dst" : "src";
216 
217 		if (fd_is_writable(write_fd) != 'W') {
218 			/* given proper replication, the reverse end should
219 			 * be readable */
220 			continue;
221 		}
222 
223 		int amt = max(rand() % 4096, 1);
224 		ssize_t ret = write(write_fd, buf, (size_t)amt);
225 		if (ret == amt) {
226 			struct shadow_fd *mod_sfd =
227 					from_src ? src_shadow : dst_shadow;
228 			mod_sfd->pipe.readable = true;
229 
230 			/* Write successful */
231 			if (shadow_sync(from_src ? &src_map : &dst_map,
232 					    from_src ? &dst_map : &src_map) ==
233 					-1) {
234 				success = false;
235 				goto cleanup;
236 			}
237 
238 			bool believe_read = can_read && !interpret_as_force_iw;
239 			bool expect_transfer_fail =
240 					(from_src && !believe_read) ||
241 					(!from_src && !can_write);
242 
243 			// todo: try multiple sync cycles (?)
244 			ssize_t rr = read(read_fd, buf, 4096);
245 			bool tf_pass = rr == amt;
246 			if (!expect_transfer_fail) {
247 				/* on some systems, pipe is bidirectional,
248 				 * making some additional transfers succeed.
249 				 * This is fine. */
250 				success = success && tf_pass;
251 			}
252 			const char *resdesc = tf_pass != expect_transfer_fail
253 							      ? "expected"
254 							      : "unexpected";
255 			if (tf_pass) {
256 				printf("Send packet to %s, and received it from %s, %s\n",
257 						target, antitarget, resdesc);
258 			} else {
259 				printf("Failed to receive packet from %s, %d %zd %s, %s\n",
260 						antitarget, read_fd, rr,
261 						strerror(errno), resdesc);
262 			}
263 		}
264 	}
265 
266 	/* Step 3: close one end, and verify that the other end is closed */
267 	// TODO: test partial shutdowns as well, all 2^4 cases for a single
268 	// cycle; and test epipe closing by queuing additional data
269 	struct shadow_fd *cls_shadow = close_src ? src_shadow : dst_shadow;
270 	if (close_src) {
271 		checked_close(opp_end);
272 		opp_end = -1;
273 	} else {
274 		checked_close(anti_end);
275 		anti_end = -1;
276 	}
277 
278 	bool shutdown_deletes = (cls_shadow->pipe.can_read &&
279 				 !cls_shadow->pipe.can_write);
280 	/* Special cases, which aren't very important */
281 	shutdown_deletes |= (interpret_as_force_iw &&
282 			     !cls_shadow->pipe.can_write && close_src);
283 
284 	cls_shadow->pipe.readable = cls_shadow->pipe.can_read;
285 	cls_shadow->pipe.writable = cls_shadow->pipe.can_write;
286 
287 	if (shadow_sync(close_src ? &src_map : &dst_map,
288 			    close_src ? &dst_map : &src_map) == -1) {
289 		success = false;
290 		goto cleanup;
291 	}
292 	bool deleted_shadows = true;
293 	if (dst_map.link.l_next != &dst_map.link) {
294 		print_pipe_state("dst", &dst_shadow->pipe);
295 		deleted_shadows = false;
296 	}
297 	if (src_map.link.l_next != &src_map.link) {
298 		print_pipe_state("src", &src_shadow->pipe);
299 		deleted_shadows = false;
300 	}
301 
302 	bool correct_teardown = deleted_shadows == shutdown_deletes;
303 	success = success && correct_teardown;
304 	printf("Deleted shadows: %c (expected %c)\n",
305 			deleted_shadows ? 'Y' : 'n',
306 			shutdown_deletes ? 'Y' : 'n');
307 
308 	printf("Test: %s\n", success ? "pass" : "FAIL");
309 cleanup:
310 	if (anti_end != -1) {
311 		checked_close(anti_end);
312 	}
313 	if (opp_end != -1) {
314 		checked_close(opp_end);
315 	}
316 	cleanup_translation_map(&src_map);
317 	cleanup_translation_map(&dst_map);
318 
319 	return success;
320 }
321 
322 log_handler_func_t log_funcs[2] = {NULL, test_log_handler};
main(int argc,char ** argv)323 int main(int argc, char **argv)
324 {
325 	(void)argc;
326 	(void)argv;
327 
328 	struct sigaction act;
329 	act.sa_handler = SIG_IGN;
330 	sigemptyset(&act.sa_mask);
331 	act.sa_flags = 0;
332 	if (sigaction(SIGPIPE, &act, NULL) == -1) {
333 		printf("Sigaction failed\n");
334 		return EXIT_SUCCESS;
335 	}
336 
337 	srand(0);
338 	bool all_success = true;
339 	for (uint32_t bits = 0; bits < 32; bits++) {
340 		bool pass = test_pipe_mirror(bits & 1, bits & 2, bits & 4,
341 				bits & 8, bits & 16);
342 		all_success = all_success && pass;
343 	}
344 	printf("\nSuccess: %c\n", all_success ? 'Y' : 'n');
345 	return all_success ? EXIT_SUCCESS : EXIT_FAILURE;
346 }
347