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
52 char *TCID = "sendmsg01";
53 int testno;
54
55 static char buf[1024], bigbuf[128 * 1024];
56 static int s;
57 static struct sockaddr_in sin1, sin2;
58 static struct sockaddr_un sun1;
59 static struct msghdr msgdat;
60 static char cbuf[4096];
61 static struct cmsghdr *control;
62 static int controllen;
63 static struct iovec iov[1];
64 static int sfd; /* shared between do_child and start_server */
65 static int ufd; /* shared between do_child and start_server */
66
67 static void setup(void);
68 static void setup0(void);
69 static void setup1(void);
70 static void setup2(void);
71 static void setup3(void);
72 static void setup4(void);
73 static void setup5(void);
74 static void setup6(void);
75 static void setup8(void);
76
77 static void cleanup(void);
78 static void cleanup0(void);
79 static void cleanup1(void);
80 static void cleanup4(void);
81
82 static void do_child(void);
83
84 struct test_case_t { /* test case structure */
85 int domain; /* PF_INET, PF_UNIX, ... */
86 int type; /* SOCK_STREAM, SOCK_DGRAM ... */
87 int proto; /* protocol number (usually 0 = default) */
88 struct iovec *iov;
89 int iovcnt; /* # elements in iovec */
90 void *buf; /* send data buffer */
91 int buflen; /* send buffer length */
92 struct msghdr *msg;
93 unsigned flags;
94 struct sockaddr *to; /* destination */
95 int tolen; /* length of "to" buffer */
96 int retval; /* syscall return value */
97 int experrno; /* expected errno */
98 void (*setup) (void);
99 void (*cleanup) (void);
100 char *desc;
101 };
102
103 struct test_case_t tdat[] = {
104 {.domain = PF_INET,
105 .type = SOCK_STREAM,
106 .proto = 0,
107 .iov = iov,
108 .iovcnt = 1,
109 .buf = buf,
110 .buflen = sizeof(buf),
111 .msg = &msgdat,
112 .flags = 0,
113 .to = (struct sockaddr *)&sin1,
114 .tolen = sizeof(sin1),
115 .retval = -1,
116 .experrno = EBADF,
117 .setup = setup0,
118 .cleanup = cleanup0,
119 .desc = "bad file descriptor"}
120 ,
121 {.domain = 0,
122 .type = 0,
123 .proto = 0,
124 .iov = iov,
125 .iovcnt = 1,
126 .buf = buf,
127 .buflen = sizeof(buf),
128 .msg = &msgdat,
129 .flags = 0,
130 .to = (struct sockaddr *)&sin1,
131 .tolen = sizeof(sin1),
132 .retval = -1,
133 .experrno = ENOTSOCK,
134 .setup = setup0,
135 .cleanup = cleanup0,
136 .desc = "invalid socket"}
137 ,
138 {.domain = PF_INET,
139 .type = SOCK_DGRAM,
140 .proto = 0,
141 .iov = iov,
142 .iovcnt = 1,
143 .buf = (void *)-1,
144 .buflen = sizeof(buf),
145 .msg = &msgdat,
146 .flags = 0,
147 .to = (struct sockaddr *)&sin1,
148 .tolen = sizeof(sin1),
149 .retval = -1,
150 .experrno = EFAULT,
151 .setup = setup1,
152 .cleanup = cleanup1,
153 .desc = "invalid send buffer"}
154 ,
155 {.domain = PF_INET,
156 .type = SOCK_STREAM,
157 .proto = 0,
158 .iov = iov,
159 .iovcnt = 1,
160 .buf = buf,
161 .buflen = sizeof(buf),
162 .msg = &msgdat,
163 .flags = 0,
164 .to = (struct sockaddr *)&sin2,
165 .tolen = sizeof(sin2),
166 .retval = 0,
167 .experrno = EFAULT,
168 .setup = setup5,
169 .cleanup = cleanup1,
170 .desc = "connected TCP"}
171 ,
172 {.domain = PF_INET,
173 .type = SOCK_STREAM,
174 .proto = 0,
175 .iov = iov,
176 .iovcnt = 1,
177 .buf = buf,
178 .buflen = sizeof(buf),
179 .msg = &msgdat,
180 .flags = 0,
181 .to = (struct sockaddr *)&sin1,
182 .tolen = sizeof(sin1),
183 .retval = -1,
184 .experrno = EPIPE,
185 .setup = setup3,
186 .cleanup = cleanup1,
187 .desc = "not connected TCP"}
188 ,
189 {.domain = PF_INET,
190 .type = SOCK_DGRAM,
191 .proto = 0,
192 .iov = iov,
193 .iovcnt = 1,
194 .buf = buf,
195 .buflen = sizeof(buf),
196 .msg = &msgdat,
197 .flags = 0,
198 .to = (struct sockaddr *)&sin1,
199 .tolen = 1,
200 .retval = -1,
201 .experrno = EINVAL,
202 .setup = setup1,
203 .cleanup = cleanup1,
204 .desc = "invalid to buffer length"},
205 {.domain = PF_INET,
206 .type = SOCK_DGRAM,
207 .proto = 0,
208 .iov = iov,
209 .iovcnt = 1,
210 .buf = buf,
211 .buflen = sizeof(buf),
212 .msg = &msgdat,
213 .flags = 0,
214 .to = (struct sockaddr *)-1,
215 .tolen = sizeof(struct sockaddr),
216 .retval = -1,
217 .experrno = EFAULT,
218 .setup = setup1,
219 .cleanup = cleanup1,
220 .desc = "invalid to buffer"},
221 {.domain = PF_INET,
222 .type = SOCK_DGRAM,
223 .proto = 0,
224 .iov = iov,
225 .iovcnt = 1,
226 .buf = bigbuf,
227 .buflen = sizeof(bigbuf),
228 .msg = &msgdat,
229 .flags = 0,
230 .to = (struct sockaddr *)&sin1,
231 .tolen = sizeof(sin1),
232 .retval = -1,
233 .experrno = EMSGSIZE,
234 .setup = setup1,
235 .cleanup = cleanup1,
236 .desc = "UDP message too big"}
237 ,
238 {.domain = PF_INET,
239 .type = SOCK_STREAM,
240 .proto = 0,
241 .iov = iov,
242 .iovcnt = 1,
243 .buf = buf,
244 .buflen = sizeof(buf),
245 .msg = &msgdat,
246 .flags = 0,
247 .to = (struct sockaddr *)&sin1,
248 .tolen = sizeof(sin1),
249 .retval = -1,
250 .experrno = EPIPE,
251 .setup = setup2,
252 .cleanup = cleanup1,
253 .desc = "local endpoint shutdown"}
254 ,
255 {.domain = PF_INET,
256 .type = SOCK_STREAM,
257 .proto = 0,
258 .iov = NULL,
259 .iovcnt = 1,
260 .buf = buf,
261 .buflen = sizeof(buf),
262 .msg = &msgdat,
263 .flags = 0,
264 .to = (struct sockaddr *)&sin1,
265 .tolen = sizeof(sin1),
266 .retval = -1,
267 .experrno = EFAULT,
268 .setup = setup1,
269 .cleanup = cleanup1,
270 .desc = "invalid iovec pointer"}
271 ,
272 {.domain = PF_INET,
273 .type = SOCK_STREAM,
274 .proto = 0,
275 .iov = iov,
276 .iovcnt = 1,
277 .buf = buf,
278 .buflen = sizeof(buf),
279 .msg = NULL,
280 .flags = 0,
281 .to = (struct sockaddr *)&sin1,
282 .tolen = sizeof(sin1),
283 .retval = -1,
284 .experrno = EFAULT,
285 .setup = setup1,
286 .cleanup = cleanup1,
287 .desc = "invalid msghdr pointer"}
288 ,
289 {.domain = PF_UNIX,
290 .type = SOCK_DGRAM,
291 .proto = 0,
292 .iov = iov,
293 .iovcnt = 1,
294 .buf = buf,
295 .buflen = sizeof(buf),
296 .msg = &msgdat,
297 .flags = 0,
298 .to = (struct sockaddr *)&sun1,
299 .tolen = sizeof(sun1),
300 .retval = 0,
301 .experrno = 0,
302 .setup = setup4,
303 .cleanup = cleanup4,
304 .desc = "rights passing"}
305 ,
306 {.domain = PF_INET,
307 .type = SOCK_DGRAM,
308 .proto = 0,
309 .iov = iov,
310 .iovcnt = 1,
311 .buf = buf,
312 .buflen = sizeof(buf),
313 .msg = &msgdat,
314 .flags = MSG_OOB,
315 .to = (struct sockaddr *)&sin1,
316 .tolen = sizeof(sin1),
317 .retval = -1,
318 .experrno = EOPNOTSUPP,
319 .setup = setup1,
320 .cleanup = cleanup1,
321 .desc = "invalid flags set"}
322 ,
323 {.domain = PF_UNIX,
324 .type = SOCK_DGRAM,
325 .proto = 0,
326 .iov = iov,
327 .iovcnt = 1,
328 .buf = buf,
329 .buflen = sizeof(buf),
330 .msg = &msgdat,
331 .flags = 0,
332 .to = (struct sockaddr *)&sun1,
333 .tolen = sizeof(sun1),
334 .retval = 0,
335 .experrno = EOPNOTSUPP,
336 .setup = setup6,
337 .cleanup = cleanup4,
338 .desc = "invalid cmsg length"}
339 ,
340 {.domain = PF_UNIX,
341 .type = SOCK_DGRAM,
342 .proto = 0,
343 .iov = iov,
344 .iovcnt = 1,
345 .buf = buf,
346 .buflen = sizeof(buf),
347 .msg = &msgdat,
348 .flags = 0,
349 .to = (struct sockaddr *)&sun1,
350 .tolen = sizeof(sun1),
351 .retval = -1,
352 .experrno = EFAULT,
353 .setup = setup8,
354 .cleanup = cleanup4,
355 .desc = "invalid cmsg pointer"}
356 };
357
358 int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
359
360 #ifdef UCLINUX
361 static char *argv0;
362 #endif
363
main(int argc,char * argv[])364 int main(int argc, char *argv[])
365 {
366 int lc;
367
368 tst_parse_opts(argc, argv, NULL, NULL);
369
370 #ifdef UCLINUX
371 argv0 = argv[0];
372 maybe_run_child(&do_child, "dd", &sfd, &ufd);
373 #endif
374
375 setup();
376
377 for (lc = 0; TEST_LOOPING(lc); ++lc) {
378 tst_count = 0;
379 for (testno = 0; testno < TST_TOTAL; ++testno) {
380 tdat[testno].setup();
381
382 iov[0].iov_base = tdat[testno].buf;
383 iov[0].iov_len = tdat[testno].buflen;
384 if (tdat[testno].type != SOCK_STREAM) {
385 msgdat.msg_name = tdat[testno].to;
386 msgdat.msg_namelen = tdat[testno].tolen;
387 }
388 msgdat.msg_iov = tdat[testno].iov;
389 msgdat.msg_iovlen = tdat[testno].iovcnt;
390 msgdat.msg_control = control;
391 msgdat.msg_controllen = controllen;
392 msgdat.msg_flags = 0;
393
394 TEST(sendmsg(s, tdat[testno].msg, tdat[testno].flags));
395
396 if (TEST_RETURN > 0)
397 TEST_RETURN = 0;
398
399 if (TEST_RETURN != tdat[testno].retval ||
400 (TEST_RETURN < 0 &&
401 TEST_ERRNO != tdat[testno].experrno)) {
402 tst_resm(TFAIL, "%s ; returned"
403 " %ld (expected %d), errno %d (expected"
404 " %d)", tdat[testno].desc,
405 TEST_RETURN, tdat[testno].retval,
406 TEST_ERRNO, tdat[testno].experrno);
407 } else {
408 tst_resm(TPASS, "%s successful",
409 tdat[testno].desc);
410 }
411 tdat[testno].cleanup();
412 }
413 }
414 cleanup();
415 tst_exit();
416 }
417
start_server(struct sockaddr_in * sin0,struct sockaddr_un * sun0)418 static pid_t start_server(struct sockaddr_in *sin0, struct sockaddr_un *sun0)
419 {
420 pid_t pid;
421 socklen_t slen = sizeof(*sin0);
422
423 sin0->sin_family = AF_INET;
424 sin0->sin_port = 0; /* pick random free port */
425 sin0->sin_addr.s_addr = INADDR_ANY;
426
427 /* set up inet socket */
428 sfd = socket(PF_INET, SOCK_STREAM, 0);
429 if (sfd < 0) {
430 tst_brkm(TBROK, cleanup, "server socket failed: %s",
431 strerror(errno));
432 return -1;
433 }
434 if (bind(sfd, (struct sockaddr *)sin0, sizeof(*sin0)) < 0) {
435 tst_brkm(TBROK, cleanup, "server bind failed: %s",
436 strerror(errno));
437 return -1;
438 }
439 if (listen(sfd, 10) < 0) {
440 tst_brkm(TBROK, cleanup, "server listen failed: %s",
441 strerror(errno));
442 return -1;
443 }
444 if (getsockname(sfd, (struct sockaddr *)sin0, &slen) == -1)
445 tst_brkm(TBROK | TERRNO, cleanup, "getsockname failed");
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
do_child(void)481 static 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
533 static pid_t pid;
534 static char tmpsunpath[1024];
535
setup(void)536 static 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
cleanup(void)568 static 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
setup0(void)576 static 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
cleanup0(void)585 static void cleanup0(void)
586 {
587 s = -1;
588 }
589
setup1(void)590 static void setup1(void)
591 {
592 s = socket(tdat[testno].domain, tdat[testno].type, tdat[testno].proto);
593 if (s < 0) {
594 tst_brkm(TBROK, cleanup, "socket setup failed: %s",
595 strerror(errno));
596 }
597 if (tdat[testno].type == SOCK_STREAM &&
598 connect(s, (struct sockaddr *)tdat[testno].to,
599 tdat[testno].tolen) < 0) {
600 tst_brkm(TBROK, cleanup, "connect failed: %s", strerror(errno));
601 }
602 }
603
cleanup1(void)604 static void cleanup1(void)
605 {
606 close(s);
607 s = -1;
608 }
609
setup2(void)610 static void setup2(void)
611 {
612 setup1(); /* get a socket in s */
613 if (shutdown(s, 1) < 0) {
614 tst_brkm(TBROK, cleanup, "socket setup failed connect "
615 "test %d: %s", testno, strerror(errno));
616 }
617 }
618
setup3(void)619 static void setup3(void)
620 {
621 s = socket(tdat[testno].domain, tdat[testno].type, tdat[testno].proto);
622 if (s < 0) {
623 tst_brkm(TBROK, cleanup, "socket setup failed: %s",
624 strerror(errno));
625 }
626 }
627
628 static char tmpfilename[1024];
629 static int tfd;
630
setup4(void)631 static void setup4(void)
632 {
633
634 setup1(); /* get a socket in s */
635
636 strcpy(tmpfilename, "sockXXXXXX");
637 tfd = mkstemp(tmpfilename);
638 if (tfd < 0) {
639 tst_brkm(TBROK, cleanup4, "socket setup failed: %s",
640 strerror(errno));
641 }
642 control = (struct cmsghdr *)cbuf;
643 memset(cbuf, 0x00, sizeof(cbuf));
644 control->cmsg_len = sizeof(struct cmsghdr) + 4;
645 control->cmsg_level = SOL_SOCKET;
646 control->cmsg_type = SCM_RIGHTS;
647 *(int *)CMSG_DATA(control) = tfd;
648 controllen = control->cmsg_len;
649 }
650
cleanup4(void)651 static void cleanup4(void)
652 {
653 cleanup1();
654 close(tfd);
655 tfd = -1;
656 control = 0;
657 controllen = 0;
658 }
659
setup5(void)660 static void setup5(void)
661 {
662 s = socket(tdat[testno].domain, tdat[testno].type, tdat[testno].proto);
663 if (s < 0) {
664 tst_brkm(TBROK, cleanup, "socket setup failed: %s",
665 strerror(errno));
666 }
667
668 if (connect(s, (struct sockaddr *)&sin1, sizeof(sin1)) < 0)
669 tst_brkm(TBROK, cleanup, "connect failed: %s", strerror(errno));
670
671 /* slight change destination (port) so connect() is to different
672 * 5-tuple than already connected
673 */
674 sin2 = sin1;
675 sin2.sin_port = tst_get_unused_port(cleanup, AF_INET, SOCK_STREAM);
676 }
677
setup6(void)678 static void setup6(void)
679 {
680 setup4();
681 /*
682 controllen = control->cmsg_len = sizeof(struct cmsghdr) - 4;
683 */
684 controllen = control->cmsg_len = 0;
685 }
686
setup8(void)687 static void setup8(void)
688 {
689 setup4();
690 control = (struct cmsghdr *)-1;
691 }
692