xref: /freebsd/tools/test/stress2/misc/sendmsg2.sh (revision ec0ea6efa1ad229d75c394c1a9b9cac33af2b1d3)
1#!/bin/sh
2
3#
4# Test scenario by Tanaka Akira <akr@fsij.org>
5# from Bug 131876 - [socket] FD leak by receiving SCM_RIGHTS by recvmsg with
6# small control message buffer
7# Fixed by 337423
8
9. ../default.cfg
10
11dir=/tmp
12odir=`pwd`
13cd $dir
14sed '1,/^EOF/d' < $odir/$0 > $dir/sendmsg2.c
15mycc -o sendmsg2 -Wall -Wextra -O0 -g sendmsg2.c || exit 1
16rm -f sendmsg2.c
17cd $odir
18
19start=`date +%s`
20/tmp/sendmsg2 &
21while [ $((`date +%s` - start)) -lt 300 ]; do
22	kill -0 $! > /dev/null 2>&1 || break
23	sleep 2
24done
25if kill -0 $! > /dev/null 2>&1; then
26	echo FAIL
27	ps -lp $!
28	procstat -k $!
29	kill -9 $!
30fi
31while pkill sendmsg2; do :; done
32wait
33s=$?
34rm -f /tmp/sendmsg2
35exit $s
36EOF
37#include <sys/socket.h>
38#include <sys/types.h>
39#include <sys/uio.h>
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <time.h>
44#include <unistd.h>
45
46#define MAX_FDS 10
47#define SEND_FDS 10
48#define RECV_FDS 3
49
50void
51test(void)
52{
53	struct msghdr msg;
54	struct iovec iov;
55	union {
56		struct cmsghdr header;
57		char bytes[CMSG_SPACE(sizeof(int)*MAX_FDS)];
58	} cmsg;
59	struct cmsghdr *cmh = &cmsg.header, *c;
60	int *fds;
61	int i;
62	int ret;
63	int sv[2];
64	char buf[1024];
65	char cmdline[1024];
66
67	snprintf(cmdline, sizeof(cmdline), "fstat -p %u", (unsigned)getpid());
68
69	ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
70	if (ret == -1) { perror("socketpair"); exit(1); }
71
72	iov.iov_base = "a";
73	iov.iov_len = 1;
74
75	cmh->cmsg_len = CMSG_LEN(sizeof(int)*SEND_FDS);
76	cmh->cmsg_level = SOL_SOCKET;
77	cmh->cmsg_type = SCM_RIGHTS;
78	fds = (int *)CMSG_DATA(cmh);
79	for (i = 0; i < SEND_FDS; i++) {
80		fds[i] = 0; /* stdin */
81	}
82
83	msg.msg_name = NULL;
84	msg.msg_namelen = 0;
85	msg.msg_iov = &iov;
86	msg.msg_iovlen = 1;
87	msg.msg_control = cmh;
88	msg.msg_controllen = CMSG_SPACE(sizeof(int)*SEND_FDS);
89	msg.msg_flags = 0;
90
91	ret = sendmsg(sv[0], &msg, 0);
92	if (ret == -1) { perror("sendmsg"); exit(1); }
93
94	iov.iov_base = buf;
95	iov.iov_len = sizeof(buf);
96
97	msg.msg_name = NULL;
98	msg.msg_namelen = 0;
99	msg.msg_iov = &iov;
100	msg.msg_iovlen = 1;
101	msg.msg_control = cmh;
102	msg.msg_controllen = CMSG_SPACE(sizeof(int)*RECV_FDS);
103	msg.msg_flags = 0;
104
105#if defined(DEBUG)
106	printf("before recvmsg: msg_controllen=%d\n", msg.msg_controllen);
107#endif
108
109	ret = recvmsg(sv[1], &msg, 0);
110	if (ret == -1) { perror("sendmsg"); exit(1); }
111
112#if defined(DEBUG)
113	printf("after recvmsg: msg_controllen=%d\n", msg.msg_controllen);
114#endif
115
116	for (c = CMSG_FIRSTHDR(&msg); c != NULL; c = CMSG_NXTHDR(&msg, c)) {
117		if (c->cmsg_len == 0) { printf("cmsg_len is zero\n"); exit(1); }
118		if (c->cmsg_level == SOL_SOCKET && c->cmsg_type == SCM_RIGHTS) {
119			int *fdp, *end;
120			printf("cmsg_len=%d\n", c->cmsg_len);
121			fdp = (int *)CMSG_DATA(c);
122			end = (int *)((char *)c + c->cmsg_len);
123			for (i = 0; fdp+i < end; i++) {
124				printf("fd[%d]=%d\n", i, fdp[i]);
125			}
126		}
127	}
128	/* Note the missing sockets close */
129}
130
131int
132main(void)
133{
134	time_t start;
135
136	alarm(600);
137	start = time(NULL);
138	while (time(NULL) - start < 300)
139		test();
140
141	return (0);
142}
143