1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2001
4 *   Copyright (c) Cyril Hrubis <chrubis@suse.cz> 2012
5 *
6 *   This program is free software;  you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation; either version 2 of the License, or
9 *   (at your option) any later version.
10 *
11 *   This program is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14 *   the GNU General Public License for more details.
15 *
16 *   You should have received a copy of the GNU General Public License
17 *   along with this program;  if not, write to the Free Software
18 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22/*
23 * Test Name: sendmsg01
24 *
25 * Test Description:
26 *  Verify that sendmsg() returns the proper errno for various failure cases
27 *
28 * HISTORY
29 *	07/2001 Ported by Wayne Boyer
30 *	05/2003 Modified by Manoj Iyer - Make setup function set up lo device.
31 */
32
33#include <stdio.h>
34#include <unistd.h>
35#include <errno.h>
36#include <string.h>
37#include <fcntl.h>
38#include <time.h>
39#include <stdlib.h>
40#include <sys/types.h>
41#include <sys/socket.h>
42#include <sys/signal.h>
43#include <sys/uio.h>
44#include <sys/un.h>
45#include <sys/file.h>
46#include <sys/wait.h>
47
48#include <netinet/in.h>
49
50#include "test.h"
51#include "safe_macros.h"
52
53char *TCID = "sendmsg01";
54int testno;
55
56static char buf[1024], bigbuf[128 * 1024];
57static int s;
58static struct sockaddr_in sin1, sin2;
59static struct sockaddr_un sun1;
60static struct msghdr msgdat;
61static char cbuf[4096];
62static struct cmsghdr *control;
63static int controllen;
64static struct iovec iov[1];
65static int sfd;			/* shared between do_child and start_server */
66static int ufd;			/* shared between do_child and start_server */
67
68static void setup(void);
69static void setup0(void);
70static void setup1(void);
71static void setup2(void);
72static void setup3(void);
73static void setup4(void);
74static void setup5(void);
75static void setup6(void);
76static void setup8(void);
77
78static void cleanup(void);
79static void cleanup0(void);
80static void cleanup1(void);
81static void cleanup4(void);
82
83static void do_child(void);
84
85struct test_case_t {		/* test case structure */
86	int domain;		/* PF_INET, PF_UNIX, ... */
87	int type;		/* SOCK_STREAM, SOCK_DGRAM ... */
88	int proto;		/* protocol number (usually 0 = default) */
89	struct iovec *iov;
90	int iovcnt;		/* # elements in iovec */
91	void *buf;		/* send data buffer */
92	int buflen;		/* send buffer length */
93	struct msghdr *msg;
94	unsigned flags;
95	struct sockaddr *to;	/* destination */
96	int tolen;		/* length of "to" buffer */
97	int retval;		/* syscall return value */
98	int experrno;		/* expected errno */
99	void (*setup) (void);
100	void (*cleanup) (void);
101	char *desc;
102};
103
104struct test_case_t tdat[] = {
105	{.domain = PF_INET,
106	 .type = SOCK_STREAM,
107	 .proto = 0,
108	 .iov = iov,
109	 .iovcnt = 1,
110	 .buf = buf,
111	 .buflen = sizeof(buf),
112	 .msg = &msgdat,
113	 .flags = 0,
114	 .to = (struct sockaddr *)&sin1,
115	 .tolen = sizeof(sin1),
116	 .retval = -1,
117	 .experrno = EBADF,
118	 .setup = setup0,
119	 .cleanup = cleanup0,
120	 .desc = "bad file descriptor"}
121	,
122	{.domain = 0,
123	 .type = 0,
124	 .proto = 0,
125	 .iov = iov,
126	 .iovcnt = 1,
127	 .buf = buf,
128	 .buflen = sizeof(buf),
129	 .msg = &msgdat,
130	 .flags = 0,
131	 .to = (struct sockaddr *)&sin1,
132	 .tolen = sizeof(sin1),
133	 .retval = -1,
134	 .experrno = ENOTSOCK,
135	 .setup = setup0,
136	 .cleanup = cleanup0,
137	 .desc = "invalid socket"}
138	,
139	{.domain = PF_INET,
140	 .type = SOCK_DGRAM,
141	 .proto = 0,
142	 .iov = iov,
143	 .iovcnt = 1,
144	 .buf = (void *)-1,
145	 .buflen = sizeof(buf),
146	 .msg = &msgdat,
147	 .flags = 0,
148	 .to = (struct sockaddr *)&sin1,
149	 .tolen = sizeof(sin1),
150	 .retval = -1,
151	 .experrno = EFAULT,
152	 .setup = setup1,
153	 .cleanup = cleanup1,
154	 .desc = "invalid send buffer"}
155	,
156	{.domain = PF_INET,
157	 .type = SOCK_STREAM,
158	 .proto = 0,
159	 .iov = iov,
160	 .iovcnt = 1,
161	 .buf = buf,
162	 .buflen = sizeof(buf),
163	 .msg = &msgdat,
164	 .flags = 0,
165	 .to = (struct sockaddr *)&sin2,
166	 .tolen = sizeof(sin2),
167	 .retval = 0,
168	 .experrno = EFAULT,
169	 .setup = setup5,
170	 .cleanup = cleanup1,
171	 .desc = "connected TCP"}
172	,
173	{.domain = PF_INET,
174	 .type = SOCK_STREAM,
175	 .proto = 0,
176	 .iov = iov,
177	 .iovcnt = 1,
178	 .buf = buf,
179	 .buflen = sizeof(buf),
180	 .msg = &msgdat,
181	 .flags = 0,
182	 .to = (struct sockaddr *)&sin1,
183	 .tolen = sizeof(sin1),
184	 .retval = -1,
185	 .experrno = EPIPE,
186	 .setup = setup3,
187	 .cleanup = cleanup1,
188	 .desc = "not connected TCP"}
189	,
190	{.domain = PF_INET,
191	 .type = SOCK_DGRAM,
192	 .proto = 0,
193	 .iov = iov,
194	 .iovcnt = 1,
195	 .buf = buf,
196	 .buflen = sizeof(buf),
197	 .msg = &msgdat,
198	 .flags = 0,
199	 .to = (struct sockaddr *)&sin1,
200	 .tolen = 1,
201	 .retval = -1,
202	 .experrno = EINVAL,
203	 .setup = setup1,
204	 .cleanup = cleanup1,
205	 .desc = "invalid to buffer length"},
206	{.domain = PF_INET,
207	 .type = SOCK_DGRAM,
208	 .proto = 0,
209	 .iov = iov,
210	 .iovcnt = 1,
211	 .buf = buf,
212	 .buflen = sizeof(buf),
213	 .msg = &msgdat,
214	 .flags = 0,
215	 .to = (struct sockaddr *)-1,
216	 .tolen = sizeof(struct sockaddr),
217	 .retval = -1,
218	 .experrno = EFAULT,
219	 .setup = setup1,
220	 .cleanup = cleanup1,
221	 .desc = "invalid to buffer"},
222	{.domain = PF_INET,
223	 .type = SOCK_DGRAM,
224	 .proto = 0,
225	 .iov = iov,
226	 .iovcnt = 1,
227	 .buf = bigbuf,
228	 .buflen = sizeof(bigbuf),
229	 .msg = &msgdat,
230	 .flags = 0,
231	 .to = (struct sockaddr *)&sin1,
232	 .tolen = sizeof(sin1),
233	 .retval = -1,
234	 .experrno = EMSGSIZE,
235	 .setup = setup1,
236	 .cleanup = cleanup1,
237	 .desc = "UDP message too big"}
238	,
239	{.domain = PF_INET,
240	 .type = SOCK_STREAM,
241	 .proto = 0,
242	 .iov = iov,
243	 .iovcnt = 1,
244	 .buf = buf,
245	 .buflen = sizeof(buf),
246	 .msg = &msgdat,
247	 .flags = 0,
248	 .to = (struct sockaddr *)&sin1,
249	 .tolen = sizeof(sin1),
250	 .retval = -1,
251	 .experrno = EPIPE,
252	 .setup = setup2,
253	 .cleanup = cleanup1,
254	 .desc = "local endpoint shutdown"}
255	,
256	{.domain = PF_INET,
257	 .type = SOCK_STREAM,
258	 .proto = 0,
259	 .iov = NULL,
260	 .iovcnt = 1,
261	 .buf = buf,
262	 .buflen = sizeof(buf),
263	 .msg = &msgdat,
264	 .flags = 0,
265	 .to = (struct sockaddr *)&sin1,
266	 .tolen = sizeof(sin1),
267	 .retval = -1,
268	 .experrno = EFAULT,
269	 .setup = setup1,
270	 .cleanup = cleanup1,
271	 .desc = "invalid iovec pointer"}
272	,
273	{.domain = PF_INET,
274	 .type = SOCK_STREAM,
275	 .proto = 0,
276	 .iov = iov,
277	 .iovcnt = 1,
278	 .buf = buf,
279	 .buflen = sizeof(buf),
280	 .msg = NULL,
281	 .flags = 0,
282	 .to = (struct sockaddr *)&sin1,
283	 .tolen = sizeof(sin1),
284	 .retval = -1,
285	 .experrno = EFAULT,
286	 .setup = setup1,
287	 .cleanup = cleanup1,
288	 .desc = "invalid msghdr pointer"}
289	,
290	{.domain = PF_UNIX,
291	 .type = SOCK_DGRAM,
292	 .proto = 0,
293	 .iov = iov,
294	 .iovcnt = 1,
295	 .buf = buf,
296	 .buflen = sizeof(buf),
297	 .msg = &msgdat,
298	 .flags = 0,
299	 .to = (struct sockaddr *)&sun1,
300	 .tolen = sizeof(sun1),
301	 .retval = 0,
302	 .experrno = 0,
303	 .setup = setup4,
304	 .cleanup = cleanup4,
305	 .desc = "rights passing"}
306	,
307	{.domain = PF_INET,
308	 .type = SOCK_DGRAM,
309	 .proto = 0,
310	 .iov = iov,
311	 .iovcnt = 1,
312	 .buf = buf,
313	 .buflen = sizeof(buf),
314	 .msg = &msgdat,
315	 .flags = MSG_OOB,
316	 .to = (struct sockaddr *)&sin1,
317	 .tolen = sizeof(sin1),
318	 .retval = -1,
319	 .experrno = EOPNOTSUPP,
320	 .setup = setup1,
321	 .cleanup = cleanup1,
322	 .desc = "invalid flags set"}
323	,
324	{.domain = PF_UNIX,
325	 .type = SOCK_DGRAM,
326	 .proto = 0,
327	 .iov = iov,
328	 .iovcnt = 1,
329	 .buf = buf,
330	 .buflen = sizeof(buf),
331	 .msg = &msgdat,
332	 .flags = 0,
333	 .to = (struct sockaddr *)&sun1,
334	 .tolen = sizeof(sun1),
335	 .retval = 0,
336	 .experrno = EOPNOTSUPP,
337	 .setup = setup6,
338	 .cleanup = cleanup4,
339	 .desc = "invalid cmsg length"}
340	,
341	{.domain = PF_UNIX,
342	 .type = SOCK_DGRAM,
343	 .proto = 0,
344	 .iov = iov,
345	 .iovcnt = 1,
346	 .buf = buf,
347	 .buflen = sizeof(buf),
348	 .msg = &msgdat,
349	 .flags = 0,
350	 .to = (struct sockaddr *)&sun1,
351	 .tolen = sizeof(sun1),
352	 .retval = -1,
353	 .experrno = EFAULT,
354	 .setup = setup8,
355	 .cleanup = cleanup4,
356	 .desc = "invalid cmsg pointer"}
357};
358
359int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
360
361#ifdef UCLINUX
362static char *argv0;
363#endif
364
365int main(int argc, char *argv[])
366{
367	int lc;
368
369	tst_parse_opts(argc, argv, NULL, NULL);
370
371#ifdef UCLINUX
372	argv0 = argv[0];
373	maybe_run_child(&do_child, "dd", &sfd, &ufd);
374#endif
375
376	setup();
377
378	for (lc = 0; TEST_LOOPING(lc); ++lc) {
379		tst_count = 0;
380		for (testno = 0; testno < TST_TOTAL; ++testno) {
381			tdat[testno].setup();
382
383			iov[0].iov_base = tdat[testno].buf;
384			iov[0].iov_len = tdat[testno].buflen;
385			if (tdat[testno].type != SOCK_STREAM) {
386				msgdat.msg_name = tdat[testno].to;
387				msgdat.msg_namelen = tdat[testno].tolen;
388			}
389			msgdat.msg_iov = tdat[testno].iov;
390			msgdat.msg_iovlen = tdat[testno].iovcnt;
391			msgdat.msg_control = control;
392			msgdat.msg_controllen = controllen;
393			msgdat.msg_flags = 0;
394
395			TEST(sendmsg(s, tdat[testno].msg, tdat[testno].flags));
396
397			if (TEST_RETURN > 0)
398				TEST_RETURN = 0;
399
400			if (TEST_RETURN != tdat[testno].retval ||
401			    (TEST_RETURN < 0 &&
402			     TEST_ERRNO != tdat[testno].experrno)) {
403				tst_resm(TFAIL, "%s ; returned"
404					 " %ld (expected %d), errno %d (expected"
405					 " %d)", tdat[testno].desc,
406					 TEST_RETURN, tdat[testno].retval,
407					 TEST_ERRNO, tdat[testno].experrno);
408			} else {
409				tst_resm(TPASS, "%s successful",
410					 tdat[testno].desc);
411			}
412			tdat[testno].cleanup();
413		}
414	}
415	cleanup();
416	tst_exit();
417}
418
419static pid_t start_server(struct sockaddr_in *sin0, struct sockaddr_un *sun0)
420{
421	pid_t pid;
422	socklen_t slen = sizeof(*sin0);
423
424	sin0->sin_family = AF_INET;
425	sin0->sin_port = 0; /* pick random free port */
426	sin0->sin_addr.s_addr = INADDR_ANY;
427
428	/* set up inet socket */
429	sfd = socket(PF_INET, SOCK_STREAM, 0);
430	if (sfd < 0) {
431		tst_brkm(TBROK, cleanup, "server socket failed: %s",
432			 strerror(errno));
433		return -1;
434	}
435	if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
436		tst_brkm(TBROK, cleanup, "server bind failed: %s",
437			 strerror(errno));
438		return -1;
439	}
440	if (listen(sfd, 10) < 0) {
441		tst_brkm(TBROK, cleanup, "server listen failed: %s",
442			 strerror(errno));
443		return -1;
444	}
445	SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)sin0, &slen);
446
447	/* set up UNIX-domain socket */
448	ufd = socket(PF_UNIX, SOCK_DGRAM, 0);
449	if (ufd < 0) {
450		tst_brkm(TBROK, cleanup, "server UD socket failed: %s",
451			 strerror(errno));
452		return -1;
453	}
454	if (bind(ufd, (struct sockaddr *)sun0, sizeof(*sun0))) {
455		tst_brkm(TBROK, cleanup, "server UD bind failed: %s",
456			 strerror(errno));
457		return -1;
458	}
459
460	switch ((pid = FORK_OR_VFORK())) {
461	case 0:
462#ifdef UCLINUX
463		if (self_exec(argv0, "dd", sfd, ufd) < 0)
464			tst_brkm(TBROK, cleanup, "server self_exec failed");
465#else
466		do_child();
467#endif
468		break;
469	case -1:
470		tst_brkm(TBROK, cleanup, "server fork failed: %s",
471			 strerror(errno));
472	default:
473		close(sfd);
474		close(ufd);
475		return pid;
476	}
477
478	exit(1);
479}
480
481static void do_child(void)
482{
483	struct sockaddr_in fsin;
484	struct sockaddr_un fsun;
485	fd_set afds, rfds;
486	int nfds, cc, fd;
487
488	FD_ZERO(&afds);
489	FD_SET(sfd, &afds);
490	FD_SET(ufd, &afds);
491
492	nfds = MAX(sfd + 1, ufd + 1);
493
494	/* accept connections until killed */
495	while (1) {
496		socklen_t fromlen;
497
498		memcpy(&rfds, &afds, sizeof(rfds));
499
500		if (select(nfds, &rfds, NULL, NULL, NULL) < 0)
501			if (errno != EINTR)
502				exit(1);
503		if (FD_ISSET(sfd, &rfds)) {
504			int newfd;
505
506			fromlen = sizeof(fsin);
507			newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen);
508			if (newfd >= 0) {
509				FD_SET(newfd, &afds);
510				nfds = MAX(nfds, newfd + 1);
511			}
512		}
513		if (FD_ISSET(ufd, &rfds)) {
514			int newfd;
515
516			fromlen = sizeof(fsun);
517			newfd = accept(ufd, (struct sockaddr *)&fsun, &fromlen);
518			if (newfd >= 0)
519				FD_SET(newfd, &afds);
520		}
521		for (fd = 0; fd < nfds; ++fd) {
522			if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) {
523				cc = read(fd, buf, sizeof(buf));
524				if (cc == 0 || (cc < 0 && errno != EINTR)) {
525					close(fd);
526					FD_CLR(fd, &afds);
527				}
528			}
529		}
530	}
531}
532
533static pid_t pid;
534static char tmpsunpath[1024];
535
536static void setup(void)
537{
538
539	int ret = 0;
540
541	tst_require_root();
542	tst_sig(FORK, DEF_HANDLER, cleanup);
543	TEST_PAUSE;
544
545
546	tst_tmpdir();
547	snprintf(tmpsunpath, 1024, "udsock%ld", (long)time(NULL));
548	sun1.sun_family = AF_UNIX;
549	strcpy(sun1.sun_path, tmpsunpath);
550
551	/* this test will fail or in some cases hang if no eth or lo is
552	 * configured, so making sure in setup that at least lo is up
553	 */
554	ret = system("ip link set lo up");
555	if (WEXITSTATUS(ret) != 0) {
556		ret = system("ifconfig lo up 127.0.0.1");
557		if (WEXITSTATUS(ret) != 0) {
558			tst_brkm(TBROK, cleanup,
559			    "ip/ifconfig failed to bring up loop back device");
560		}
561	}
562
563	pid = start_server(&sin1, &sun1);
564
565	signal(SIGPIPE, SIG_IGN);
566}
567
568static void cleanup(void)
569{
570	if (pid > 0)
571		kill(pid, SIGKILL);	/* kill server, if server exists */
572	unlink(tmpsunpath);
573	tst_rmdir();
574}
575
576static void setup0(void)
577{
578	if (tdat[testno].experrno == EBADF)
579		s = 400;	/* anything not an open file */
580	else if ((s = open("/dev/null", O_WRONLY)) == -1)
581		tst_brkm(TBROK, cleanup, "error opening /dev/null - "
582			 "errno: %s", strerror(errno));
583}
584
585static void cleanup0(void)
586{
587	s = -1;
588}
589
590static void setup1(void)
591{
592	s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
593			tdat[testno].proto);
594	if (tdat[testno].type == SOCK_STREAM &&
595	    connect(s, (struct sockaddr *)tdat[testno].to,
596		    tdat[testno].tolen) < 0) {
597		tst_brkm(TBROK, cleanup, "connect failed: %s", strerror(errno));
598	}
599}
600
601static void cleanup1(void)
602{
603	close(s);
604	s = -1;
605}
606
607static void setup2(void)
608{
609	setup1();		/* get a socket in s */
610	if (shutdown(s, 1) < 0) {
611		tst_brkm(TBROK, cleanup, "socket setup failed connect "
612			 "test %d: %s", testno, strerror(errno));
613	}
614}
615
616static void setup3(void)
617{
618	s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
619		        tdat[testno].proto);
620}
621
622static char tmpfilename[1024];
623static int tfd;
624
625static void setup4(void)
626{
627
628	setup1();		/* get a socket in s */
629
630	strcpy(tmpfilename, "sockXXXXXX");
631	tfd = mkstemp(tmpfilename);
632	if (tfd < 0) {
633		tst_brkm(TBROK, cleanup4, "socket setup failed: %s",
634			 strerror(errno));
635	}
636	control = (struct cmsghdr *)cbuf;
637	memset(cbuf, 0x00, sizeof(cbuf));
638	control->cmsg_len = sizeof(struct cmsghdr) + 4;
639	control->cmsg_level = SOL_SOCKET;
640	control->cmsg_type = SCM_RIGHTS;
641	*(int *)CMSG_DATA(control) = tfd;
642	controllen = control->cmsg_len;
643}
644
645static void cleanup4(void)
646{
647	cleanup1();
648	close(tfd);
649	tfd = -1;
650	control = 0;
651	controllen = 0;
652}
653
654static void setup5(void)
655{
656	s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
657			tdat[testno].proto);
658
659	SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sin1, sizeof(sin1));
660
661	/* slight change destination (port) so connect() is to different
662	 * 5-tuple than already connected
663	 */
664	sin2 = sin1;
665	sin2.sin_port = tst_get_unused_port(cleanup, AF_INET, SOCK_STREAM);
666}
667
668static void setup6(void)
669{
670	setup4();
671/*
672	controllen = control->cmsg_len = sizeof(struct cmsghdr) - 4;
673*/
674	controllen = control->cmsg_len = 0;
675}
676
677static void setup8(void)
678{
679	setup4();
680	control = (struct cmsghdr *)-1;
681}
682