1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  * Test Name: recvmsg01
22  *
23  * Test Description:
24  *  Verify that recvmsg() returns the proper errno for various failure cases
25  *
26  * Usage:  <for command-line>
27  *  recvmsg01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
28  *     where,  -c n : Run n copies concurrently.
29  *             -e   : Turn on errno logging.
30  *	       -i n : Execute test n times.
31  *	       -I x : Execute test for x seconds.
32  *	       -P x : Pause for x seconds between iterations.
33  *	       -t   : Turn on syscall timing.
34  *
35  * HISTORY
36  *	07/2001 Ported by Wayne Boyer
37  *
38  * RESTRICTIONS:
39  *  None.
40  *
41  */
42 
43 #include <stdio.h>
44 #include <unistd.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 
49 #include <sys/wait.h>
50 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <sys/signal.h>
53 #include <sys/uio.h>
54 #include <sys/un.h>
55 #include <sys/file.h>
56 
57 #include <netinet/in.h>
58 
59 #include "test.h"
60 #include "safe_macros.h"
61 
62 char *TCID = "recvmsg01";
63 int testno;
64 
65 char buf[1024], cbuf[1024];
66 int s;				/* socket descriptor */
67 int passed_fd = -1;		/* rights-passing test descriptor */
68 struct sockaddr_in sin1, from;
69 struct sockaddr_un sun1;
70 struct msghdr msgdat;
71 struct cmsghdr *control = 0;
72 int controllen = 0;
73 struct iovec iov[1];
74 static int sfd;			/* shared between do_child and start_server */
75 static int ufd;			/* shared between do_child and start_server */
76 
77 void setup(void);
78 void setup0(void);
79 void setup1(void);
80 void setup2(void);
81 void setup3(void);
82 void setup4(void);
83 void cleanup(void);
84 void cleanup0(void);
85 void cleanup1(void);
86 void cleanup2(void);
87 void do_child(void);
88 
89 void sender(int);
90 pid_t start_server(struct sockaddr_in *, struct sockaddr_un *);
91 
92 struct test_case_t {		/* test case structure */
93 	int domain;		/* PF_INET, PF_UNIX, ... */
94 	int type;		/* SOCK_STREAM, SOCK_DGRAM ... */
95 	int proto;		/* protocol number (usually 0 = default) */
96 	struct iovec *iov;
97 	int iovcnt;
98 	void *buf;		/* recv data buffer */
99 	int buflen;		/* recv buffer length */
100 	struct msghdr *msg;
101 	unsigned flags;
102 	struct sockaddr *from;	/* from address */
103 	int fromlen;		/* from address value/result buffer length */
104 	int retval;		/* syscall return value */
105 	int experrno;		/* expected errno */
106 	void (*setup) (void);
107 	void (*cleanup) (void);
108 	char *desc;
109 } tdat[] = {
110 /* 1 */
111 	{
112 	PF_INET, SOCK_STREAM, 0, iov, 1, buf, sizeof(buf), &msgdat, 0,
113 		    (struct sockaddr *)&from, sizeof(from),
114 		    -1, EBADF, setup0, cleanup0, "bad file descriptor"}
115 	,
116 /* 2 */
117 	{
118 	0, 0, 0, iov, 1, (void *)buf, sizeof(buf), &msgdat, 0,
119 		    (struct sockaddr *)&from, sizeof(from),
120 		    -1, ENOTSOCK, setup0, cleanup0, "invalid socket"}
121 	,
122 /* 3 */
123 	{
124 	PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf),
125 		    &msgdat, 0, (struct sockaddr *)-1, sizeof(from), 0,
126 		    ENOTSOCK, setup1, cleanup1, "invalid socket buffer"}
127 	,
128 /* 4 */
129 	{
130 	PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf),
131 		    &msgdat, -1, (struct sockaddr *)&from, -1, -1,
132 		    EINVAL, setup1, cleanup1, "invalid socket length"},
133 /* 5 */
134 	{
135 	PF_INET, SOCK_STREAM, 0, iov, 1, (void *)-1, sizeof(buf),
136 		    &msgdat, 0, (struct sockaddr *)&from, sizeof(from),
137 		    -1, EFAULT, setup1, cleanup1, "invalid recv buffer"}
138 	,
139 /* 6 */
140 	{
141 	PF_INET, SOCK_STREAM, 0, 0, 1, (void *)buf, sizeof(buf),
142 		    &msgdat, 0, (struct sockaddr *)&from, sizeof(from),
143 		    -1, EFAULT, setup1, cleanup1, "invalid iovec buffer"}
144 	,
145 /* 7 */
146 	{
147 	PF_INET, SOCK_STREAM, 0, iov, -1, (void *)buf, sizeof(buf),
148 		    &msgdat, 0, (struct sockaddr *)&from, sizeof(from),
149 		    -1, EMSGSIZE, setup1, cleanup1, "invalid iovec count"}
150 	,
151 /* 8 */
152 	{
153 	PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf),
154 		    &msgdat, 0, (struct sockaddr *)&from, sizeof(from),
155 		    0, 0, setup2, cleanup2, "rights reception"}
156 	,
157 /* 9 */
158 	{
159 	PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf),
160 		    &msgdat, MSG_OOB, (struct sockaddr *)&from,
161 		    sizeof(from), -1, EINVAL, setup1, cleanup1,
162 		    "invalid MSG_OOB flag set"}
163 	,
164 /* 10 */
165 	{
166 	PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf),
167 		    &msgdat, MSG_ERRQUEUE, (struct sockaddr *)&from,
168 		    sizeof(from), -1, EAGAIN, setup1, cleanup1,
169 		    "invalid MSG_ERRQUEUE flag set"}
170 	,
171 /* 11 */
172 	{
173 	PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf),
174 		    &msgdat, 0, (struct sockaddr *)&from, sizeof(from),
175 		    0, EINVAL, setup3, cleanup2, "invalid cmsg length"}
176 	,
177 /* 12 */
178 	{
179 	PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf),
180 		    &msgdat, 0, (struct sockaddr *)&from, sizeof(from),
181 		    0, 0, setup4, cleanup2, "large cmesg length"}
182 ,};
183 
184 int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
185 
186 #ifdef UCLINUX
187 static char *argv0;
188 #endif
189 
main(int argc,char * argv[])190 int main(int argc, char *argv[])
191 {
192 	int lc;
193 
194 	tst_parse_opts(argc, argv, NULL, NULL);
195 #ifdef UCLINUX
196 	argv0 = argv[0];
197 	maybe_run_child(&do_child, "dd", &sfd, &ufd);
198 #endif
199 
200 	setup();
201 
202 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
203 		tst_count = 0;
204 		for (testno = 0; testno < TST_TOTAL; ++testno) {
205 			if ((tst_kvercmp(3, 17, 0) < 0)
206 			    && (tdat[testno].flags & MSG_ERRQUEUE)
207 			    && (tdat[testno].type & SOCK_STREAM)) {
208 				tst_resm(TCONF, "skip MSG_ERRQUEUE test, "
209 						"it's supported from 3.17");
210 				continue;
211 			}
212 
213 			tdat[testno].setup();
214 
215 			/* setup common to all tests */
216 			iov[0].iov_base = tdat[testno].buf;
217 			iov[0].iov_len = tdat[testno].buflen;
218 			msgdat.msg_name = tdat[testno].from;
219 			msgdat.msg_namelen = tdat[testno].fromlen;
220 			msgdat.msg_iov = tdat[testno].iov;
221 			msgdat.msg_iovlen = tdat[testno].iovcnt;
222 			msgdat.msg_control = control;
223 			msgdat.msg_controllen = controllen;
224 			msgdat.msg_flags = 0;
225 
226 			TEST(recvmsg(s, tdat[testno].msg, tdat[testno].flags));
227 			if (TEST_RETURN >= 0)
228 				TEST_RETURN = 0;	/* all nonzero equal here */
229 			if (TEST_RETURN != tdat[testno].retval ||
230 			    (TEST_RETURN < 0 &&
231 			     TEST_ERRNO != tdat[testno].experrno)) {
232 				tst_resm(TFAIL, "%s ; returned"
233 					 " %ld (expected %d), errno %d (expected"
234 					 " %d)", tdat[testno].desc,
235 					 TEST_RETURN, tdat[testno].retval,
236 					 TEST_ERRNO, tdat[testno].experrno);
237 			} else {
238 				tst_resm(TPASS, "%s successful",
239 					 tdat[testno].desc);
240 			}
241 			tdat[testno].cleanup();
242 		}
243 	}
244 	cleanup();
245 
246 	tst_exit();
247 }
248 
249 pid_t pid;
250 char tmpsunpath[1024];
251 
setup(void)252 void setup(void)
253 {
254 	int tfd;
255 	TEST_PAUSE;
256 
257 	tst_tmpdir();
258 	(void)strcpy(tmpsunpath, "udsockXXXXXX");
259 	tfd = mkstemp(tmpsunpath);
260 	close(tfd);
261 	unlink(tmpsunpath);
262 	sun1.sun_family = AF_UNIX;
263 	(void)strcpy(sun1.sun_path, tmpsunpath);
264 
265 	signal(SIGPIPE, SIG_IGN);
266 
267 	pid = start_server(&sin1, &sun1);
268 }
269 
cleanup(void)270 void cleanup(void)
271 {
272 	if (pid > 0) {
273 		(void)kill(pid, SIGKILL);	/* kill server */
274 		wait(NULL);
275 	}
276 	if (tmpsunpath[0] != '\0')
277 		(void)unlink(tmpsunpath);
278 	tst_rmdir();
279 
280 }
281 
setup0(void)282 void setup0(void)
283 {
284 	if (tdat[testno].experrno == EBADF)
285 		s = 400;	/* anything not an open file */
286 	else if ((s = open("/dev/null", O_WRONLY)) == -1)
287 		tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed");
288 }
289 
cleanup0(void)290 void cleanup0(void)
291 {
292 	s = -1;
293 }
294 
setup1(void)295 void setup1(void)
296 {
297 	fd_set rdfds;
298 	struct timeval timeout;
299 	int n;
300 
301 	s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
302 			tdat[testno].proto);
303 	if (tdat[testno].type == SOCK_STREAM) {
304 		if (tdat[testno].domain == PF_INET) {
305 			SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sin1,
306 				     sizeof(sin1));
307 			/* Wait for something to be readable, else we won't detect EFAULT on recv */
308 			FD_ZERO(&rdfds);
309 			FD_SET(s, &rdfds);
310 			timeout.tv_sec = 2;
311 			timeout.tv_usec = 0;
312 			n = select(s + 1, &rdfds, 0, 0, &timeout);
313 			if (n != 1 || !FD_ISSET(s, &rdfds))
314 				tst_brkm(TBROK, cleanup,
315 					 "client setup1 failed - no message ready in 2 sec");
316 		} else if (tdat[testno].domain == PF_UNIX) {
317 			SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sun1,
318 				     sizeof(sun1));
319 		}
320 	}
321 }
322 
setup2(void)323 void setup2(void)
324 {
325 	setup1();
326 	if (write(s, "R", 1) < 0)
327 		tst_brkm(TBROK | TERRNO, cleanup, "test setup failed: write:");
328 	control = (struct cmsghdr *)cbuf;
329 	controllen = control->cmsg_len = sizeof(cbuf);
330 }
331 
setup3(void)332 void setup3(void)
333 {
334 	setup2();
335 	controllen = sizeof(struct cmsghdr) - 1;
336 }
337 
setup4(void)338 void setup4(void)
339 {
340 	setup2();
341 	controllen = 128 * 1024;
342 }
343 
cleanup1(void)344 void cleanup1(void)
345 {
346 	(void)close(s);
347 	close(ufd);
348 	close(sfd);
349 	s = -1;
350 }
351 
cleanup2(void)352 void cleanup2(void)
353 {
354 	close(ufd);
355 	close(sfd);
356 	(void)close(s);
357 	s = -1;
358 
359 	if (passed_fd >= 0)
360 		(void)close(passed_fd);
361 	passed_fd = -1;
362 	control = 0;
363 	controllen = 0;
364 }
365 
start_server(struct sockaddr_in * ssin,struct sockaddr_un * ssun)366 pid_t start_server(struct sockaddr_in *ssin, struct sockaddr_un *ssun)
367 {
368 	pid_t pid;
369 	socklen_t slen = sizeof(*ssin);
370 
371 	ssin->sin_family = AF_INET;
372 	ssin->sin_port = 0; /* pick random free port */
373 	ssin->sin_addr.s_addr = INADDR_ANY;
374 
375 	/* set up inet socket */
376 	sfd = socket(PF_INET, SOCK_STREAM, 0);
377 	if (sfd < 0) {
378 		tst_brkm(TBROK | TERRNO, cleanup, "server socket failed");
379 		return -1;
380 	}
381 	if (bind(sfd, (struct sockaddr *)ssin, sizeof(*ssin)) < 0) {
382 		tst_brkm(TBROK | TERRNO, cleanup, "server bind failed");
383 		return -1;
384 	}
385 	if (listen(sfd, 10) < 0) {
386 		tst_brkm(TBROK | TERRNO, cleanup, "server listen failed");
387 		return -1;
388 	}
389 	SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)ssin, &slen);
390 
391 	/* set up UNIX-domain socket */
392 	ufd = socket(PF_UNIX, SOCK_STREAM, 0);
393 	if (ufd < 0) {
394 		tst_brkm(TBROK | TERRNO, cleanup, "server UD socket failed");
395 		return -1;
396 	}
397 	if (bind(ufd, (struct sockaddr *)ssun, sizeof(*ssun))) {
398 		tst_brkm(TBROK | TERRNO, cleanup, "server UD bind failed");
399 		return -1;
400 	}
401 	if (listen(ufd, 10) < 0) {
402 		tst_brkm(TBROK | TERRNO, cleanup, "server UD listen failed");
403 		return -1;
404 	}
405 
406 	switch ((pid = FORK_OR_VFORK())) {
407 	case 0:		/* child */
408 #ifdef UCLINUX
409 		if (self_exec(argv0, "dd", sfd, ufd) < 0)
410 			tst_brkm(TBROK | TERRNO, cleanup,
411 				 "server self_exec failed");
412 #else
413 		do_child();
414 #endif
415 		break;
416 	case -1:
417 		tst_brkm(TBROK | TERRNO, cleanup, "server fork failed");
418 		/* fall through */
419 	default:		/* parent */
420 		(void)close(sfd);
421 		(void)close(ufd);
422 		return pid;
423 	}
424 	exit(1);
425 }
426 
do_child(void)427 void do_child(void)
428 {
429 	struct sockaddr_in fsin;
430 	struct sockaddr_un fsun;
431 	fd_set afds, rfds;
432 	int nfds, cc, fd;
433 
434 	FD_ZERO(&afds);
435 	FD_SET(sfd, &afds);
436 	FD_SET(ufd, &afds);
437 
438 	nfds = MAX(sfd + 1, ufd + 1);
439 
440 	/* accept connections until killed */
441 	while (1) {
442 		socklen_t fromlen;
443 
444 		memcpy(&rfds, &afds, sizeof(rfds));
445 
446 		if (select(nfds, &rfds, NULL, NULL,
447 			   NULL) < 0) {
448 			if (errno != EINTR) {
449 				perror("server select");
450 				exit(1);
451 			}
452 			continue;
453 		}
454 		if (FD_ISSET(sfd, &rfds)) {
455 			int newfd;
456 
457 			fromlen = sizeof(fsin);
458 			newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
459 			if (newfd >= 0) {
460 				FD_SET(newfd, &afds);
461 				nfds = MAX(nfds, newfd + 1);
462 				/* send something back */
463 				(void)write(newfd, "hoser\n", 6);
464 			}
465 		}
466 		if (FD_ISSET(ufd, &rfds)) {
467 			int newfd;
468 
469 			fromlen = sizeof(fsun);
470 			newfd = accept(ufd, (struct sockaddr *)&fsun, &fromlen);
471 			if (newfd >= 0) {
472 				FD_SET(newfd, &afds);
473 				nfds = MAX(nfds, newfd + 1);
474 			}
475 		}
476 		for (fd = 0; fd < nfds; ++fd)
477 			if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) {
478 				char rbuf[1024];
479 
480 				cc = read(fd, rbuf, sizeof(rbuf));
481 				if (cc && rbuf[0] == 'R')
482 					sender(fd);
483 				if (cc == 0 || (cc < 0 && errno != EINTR)) {
484 					(void)close(fd);
485 					FD_CLR(fd, &afds);
486 				}
487 			}
488 	}
489 }
490 
491 #define TM	"from recvmsg01 server"
492 
493 /* special for rights-passing test */
sender(int fd)494 void sender(int fd)
495 {
496 	struct msghdr mh;
497 	struct cmsghdr *control;
498 	char tmpfn[1024], snd_cbuf[1024];
499 	int tfd;
500 
501 	(void)strcpy(tmpfn, "smtXXXXXX");
502 	tfd = mkstemp(tmpfn);
503 	if (tfd < 0)
504 		return;
505 
506 	memset(&mh, 0x00, sizeof(mh));
507 
508 	/* set up cmsghdr */
509 	control = (struct cmsghdr *)snd_cbuf;
510 	memset(control, 0x00, sizeof(struct cmsghdr));
511 	control->cmsg_len = sizeof(struct cmsghdr) + 4;
512 	control->cmsg_level = SOL_SOCKET;
513 	control->cmsg_type = SCM_RIGHTS;
514 	*(int *)CMSG_DATA(control) = tfd;
515 
516 	/* set up msghdr */
517 	iov[0].iov_base = TM;
518 	iov[0].iov_len = sizeof(TM);
519 	mh.msg_iov = iov;
520 	mh.msg_iovlen = 1;
521 	mh.msg_flags = 0;
522 	mh.msg_control = control;
523 	mh.msg_controllen = control->cmsg_len;
524 
525 	/* do it */
526 	(void)sendmsg(fd, &mh, 0);
527 	(void)close(tfd);
528 	(void)unlink(tmpfn);
529 }
530