xref: /illumos-gate/usr/src/test/os-tests/tests/sockfs/rights.c (revision 480497bc2ff96b447dc09403a6c187a1593ac1ec)
1d865fc92SAndy Fiddaman /*
2d865fc92SAndy Fiddaman  * This file and its contents are supplied under the terms of the
3d865fc92SAndy Fiddaman  * Common Development and Distribution License ("CDDL"), version 1.0.
4d865fc92SAndy Fiddaman  * You may only use this file in accordance with the terms of version
5d865fc92SAndy Fiddaman  * 1.0 of the CDDL.
6d865fc92SAndy Fiddaman  *
7d865fc92SAndy Fiddaman  * A full copy of the text of the CDDL should have accompanied this
8d865fc92SAndy Fiddaman  * source.  A copy of the CDDL is also available via the Internet at
9d865fc92SAndy Fiddaman  * http://www.illumos.org/license/CDDL.
10d865fc92SAndy Fiddaman  */
11d865fc92SAndy Fiddaman 
12d865fc92SAndy Fiddaman /*
13d865fc92SAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
14*480497bcSJason King  * Copyright 2020 Joyent, Inc.
15d865fc92SAndy Fiddaman  */
16d865fc92SAndy Fiddaman 
17d865fc92SAndy Fiddaman /*
18d865fc92SAndy Fiddaman  * Test file descriptor passing via SCM_RIGHTS, and in particular what happens
19d865fc92SAndy Fiddaman  * on message truncation in terms of the represented size of the data in the
20d865fc92SAndy Fiddaman  * control message. Ensure that no file descriptors are leaked - the kernel
21d865fc92SAndy Fiddaman  * must close any that would not fit in the available buffer space and the
22d865fc92SAndy Fiddaman  * userland application must close the rest.
23d865fc92SAndy Fiddaman  */
24d865fc92SAndy Fiddaman 
25d865fc92SAndy Fiddaman #include <stdio.h>
26d865fc92SAndy Fiddaman #include <errno.h>
27d865fc92SAndy Fiddaman #include <fcntl.h>
28d865fc92SAndy Fiddaman #include <signal.h>
29d865fc92SAndy Fiddaman #include <stdlib.h>
30d865fc92SAndy Fiddaman #include <string.h>
31d865fc92SAndy Fiddaman #include <strings.h>
32d865fc92SAndy Fiddaman #include <unistd.h>
33d865fc92SAndy Fiddaman #include <libproc.h>
34d865fc92SAndy Fiddaman 
35d865fc92SAndy Fiddaman #include <sys/types.h>
36d865fc92SAndy Fiddaman #include <sys/param.h>
37d865fc92SAndy Fiddaman #include <sys/socket.h>
38d865fc92SAndy Fiddaman #include <sys/stat.h>
39d865fc92SAndy Fiddaman #include <sys/un.h>
40d865fc92SAndy Fiddaman #include <sys/wait.h>
41d865fc92SAndy Fiddaman #include <assert.h>
42d865fc92SAndy Fiddaman #include <alloca.h>
43d865fc92SAndy Fiddaman #include <err.h>
44d865fc92SAndy Fiddaman 
45d865fc92SAndy Fiddaman static boolean_t debug;
46d865fc92SAndy Fiddaman 
47d865fc92SAndy Fiddaman typedef struct cmsg_test {
48d865fc92SAndy Fiddaman 	char *name;		/* Name of the test */
49d865fc92SAndy Fiddaman 	uint_t send;		/* Number of FDs to send */
50d865fc92SAndy Fiddaman 	uint_t recv;		/* Size receive buffer for this number of FDs */
51d865fc92SAndy Fiddaman 	size_t predata;		/* Prepend dummy cmsg of this size */
52d865fc92SAndy Fiddaman 	int bufsize;		/* Explicitly set receive buffer size. */
53d865fc92SAndy Fiddaman 				/* Overrides 'recv' if non-zero */
54d865fc92SAndy Fiddaman 	uint_t x_controllen;	/* Expected received msg_controllen */
55d865fc92SAndy Fiddaman 	uint_t x_cmsg_datalen;	/* Expected received cmsg data length */
56d865fc92SAndy Fiddaman 	uint32_t x_flags;	/* Expected received msf_flags */
57d865fc92SAndy Fiddaman } cmsg_test_t;
58d865fc92SAndy Fiddaman 
59d865fc92SAndy Fiddaman static cmsg_test_t tests[] = {
60d865fc92SAndy Fiddaman 	{
61d865fc92SAndy Fiddaman 		.name = "send 1, recv 1",
62d865fc92SAndy Fiddaman 		.send = 1,
63d865fc92SAndy Fiddaman 		.recv = 1,
64d865fc92SAndy Fiddaman 		.predata = 0,
65d865fc92SAndy Fiddaman 		.bufsize = 0,
66d865fc92SAndy Fiddaman 		.x_controllen = 16,
67d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 4,
68d865fc92SAndy Fiddaman 		.x_flags = 0,
69d865fc92SAndy Fiddaman 	},
70d865fc92SAndy Fiddaman 	{
71d865fc92SAndy Fiddaman 		.name = "send 10, recv 10",
72d865fc92SAndy Fiddaman 		.send = 10,
73d865fc92SAndy Fiddaman 		.recv = 10,
74d865fc92SAndy Fiddaman 		.predata = 0,
75d865fc92SAndy Fiddaman 		.bufsize = 0,
76d865fc92SAndy Fiddaman 		.x_controllen = 52,
77d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 40,
78d865fc92SAndy Fiddaman 		.x_flags = 0,
79d865fc92SAndy Fiddaman 	},
80d865fc92SAndy Fiddaman 	{
81d865fc92SAndy Fiddaman 		.name = "send 2, recv 1",
82d865fc92SAndy Fiddaman 		.send = 2,
83d865fc92SAndy Fiddaman 		.recv = 1,
84d865fc92SAndy Fiddaman 		.predata = 0,
85d865fc92SAndy Fiddaman 		.bufsize = 0,
86d865fc92SAndy Fiddaman 		.x_controllen = 16,
87d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 4,
88d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
89d865fc92SAndy Fiddaman 	},
90d865fc92SAndy Fiddaman 	{
91d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, buffer 5",
92d865fc92SAndy Fiddaman 		.send = 2,
93d865fc92SAndy Fiddaman 		.recv = 1,
94d865fc92SAndy Fiddaman 		.predata = 0,
95d865fc92SAndy Fiddaman 		.bufsize = sizeof (int) * 2 - 3,
96d865fc92SAndy Fiddaman 		.x_controllen = 17,
97d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 5,
98d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
99d865fc92SAndy Fiddaman 	},
100d865fc92SAndy Fiddaman 	{
101d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, buffer 6",
102d865fc92SAndy Fiddaman 		.send = 2,
103d865fc92SAndy Fiddaman 		.recv = 1,
104d865fc92SAndy Fiddaman 		.predata = 0,
105d865fc92SAndy Fiddaman 		.bufsize = sizeof (int) * 2 - 2,
106d865fc92SAndy Fiddaman 		.x_controllen = 18,
107d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 6,
108d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
109d865fc92SAndy Fiddaman 	},
110d865fc92SAndy Fiddaman 	{
111d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, buffer 7",
112d865fc92SAndy Fiddaman 		.send = 2,
113d865fc92SAndy Fiddaman 		.recv = 1,
114d865fc92SAndy Fiddaman 		.predata = 0,
115d865fc92SAndy Fiddaman 		.bufsize = sizeof (int) * 2 - 1,
116d865fc92SAndy Fiddaman 		.x_controllen = 19,
117d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 7,
118d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
119d865fc92SAndy Fiddaman 	},
120d865fc92SAndy Fiddaman 
121d865fc92SAndy Fiddaman 	/* Tests where there is no room allowed for data */
122d865fc92SAndy Fiddaman 
123d865fc92SAndy Fiddaman 	{
124d865fc92SAndy Fiddaman 		.name = "send 2, recv 0, hdronly",
125d865fc92SAndy Fiddaman 		.send = 2,
126d865fc92SAndy Fiddaman 		.recv = 0,
127d865fc92SAndy Fiddaman 		.predata = 0,
128d865fc92SAndy Fiddaman 		.bufsize = 0,
129d865fc92SAndy Fiddaman 		.x_controllen = 12,
130d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 0,
131d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
132d865fc92SAndy Fiddaman 	},
133d865fc92SAndy Fiddaman 
134d865fc92SAndy Fiddaman 	{
135d865fc92SAndy Fiddaman 		.name = "send 2, recv 0, hdr - 1",
136d865fc92SAndy Fiddaman 		.send = 2,
137d865fc92SAndy Fiddaman 		.recv = 0,
138d865fc92SAndy Fiddaman 		.predata = 0,
139d865fc92SAndy Fiddaman 		.bufsize = -1,
140d865fc92SAndy Fiddaman 		.x_controllen = 11,
141d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 0,
142d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
143d865fc92SAndy Fiddaman 	},
144d865fc92SAndy Fiddaman 
145d865fc92SAndy Fiddaman 	{
146d865fc92SAndy Fiddaman 		.name = "send 2, recv 0, hdr - 5",
147d865fc92SAndy Fiddaman 		.send = 2,
148d865fc92SAndy Fiddaman 		.recv = 0,
149d865fc92SAndy Fiddaman 		.predata = 0,
150d865fc92SAndy Fiddaman 		.bufsize = -5,
151d865fc92SAndy Fiddaman 		.x_controllen = 7,
152d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 0,
153d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
154d865fc92SAndy Fiddaman 	},
155d865fc92SAndy Fiddaman 
156d865fc92SAndy Fiddaman 	/* Tests where SCM_RIGHTS is not the first message */
157d865fc92SAndy Fiddaman 
158d865fc92SAndy Fiddaman 	{
159d865fc92SAndy Fiddaman 		.name = "send 1, recv 1, pre 8",
160d865fc92SAndy Fiddaman 		.send = 1,
161d865fc92SAndy Fiddaman 		.recv = 1,
162d865fc92SAndy Fiddaman 		.predata = 8,
163d865fc92SAndy Fiddaman 		.bufsize = 0,
164d865fc92SAndy Fiddaman 		.x_controllen = 36,
165d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 4,
166d865fc92SAndy Fiddaman 		.x_flags = 0,
167d865fc92SAndy Fiddaman 	},
168d865fc92SAndy Fiddaman 	{
169d865fc92SAndy Fiddaman 		.name = "send 1, recv 1, pre 7",
170d865fc92SAndy Fiddaman 		.send = 1,
171d865fc92SAndy Fiddaman 		.recv = 1,
172d865fc92SAndy Fiddaman 		.predata = 7,
173d865fc92SAndy Fiddaman 		.bufsize = 0,
174d865fc92SAndy Fiddaman 		.x_controllen = 35,
175d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 4,
176d865fc92SAndy Fiddaman 		.x_flags = 0,
177d865fc92SAndy Fiddaman 	},
178d865fc92SAndy Fiddaman 	{
179d865fc92SAndy Fiddaman 		.name = "send 1, recv 1, pre 6",
180d865fc92SAndy Fiddaman 		.send = 1,
181d865fc92SAndy Fiddaman 		.recv = 1,
182d865fc92SAndy Fiddaman 		.predata = 6,
183d865fc92SAndy Fiddaman 		.bufsize = 0,
184d865fc92SAndy Fiddaman 		.x_controllen = 34,
185d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 4,
186d865fc92SAndy Fiddaman 		.x_flags = 0,
187d865fc92SAndy Fiddaman 	},
188d865fc92SAndy Fiddaman 	{
189d865fc92SAndy Fiddaman 		.name = "send 1, recv 1, pre 5",
190d865fc92SAndy Fiddaman 		.send = 1,
191d865fc92SAndy Fiddaman 		.recv = 1,
192d865fc92SAndy Fiddaman 		.predata = 5,
193d865fc92SAndy Fiddaman 		.bufsize = 0,
194d865fc92SAndy Fiddaman 		.x_controllen = 33,
195d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 4,
196d865fc92SAndy Fiddaman 		.x_flags = 0,
197d865fc92SAndy Fiddaman 	},
198d865fc92SAndy Fiddaman 
199d865fc92SAndy Fiddaman 	{
200d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 8",
201d865fc92SAndy Fiddaman 		.send = 2,
202d865fc92SAndy Fiddaman 		.recv = 1,
203d865fc92SAndy Fiddaman 		.predata = 8,
204d865fc92SAndy Fiddaman 		.bufsize = 0,
205d865fc92SAndy Fiddaman 		.x_controllen = 36,
206d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
207d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
208d865fc92SAndy Fiddaman 	},
209d865fc92SAndy Fiddaman 	{
210d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 7",
211d865fc92SAndy Fiddaman 		.send = 2,
212d865fc92SAndy Fiddaman 		.recv = 1,
213d865fc92SAndy Fiddaman 		.predata = 7,
214d865fc92SAndy Fiddaman 		.bufsize = 0,
215d865fc92SAndy Fiddaman 		.x_controllen = 36,
216d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
217d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
218d865fc92SAndy Fiddaman 	},
219d865fc92SAndy Fiddaman 	{
220d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 6",
221d865fc92SAndy Fiddaman 		.send = 2,
222d865fc92SAndy Fiddaman 		.recv = 1,
223d865fc92SAndy Fiddaman 		.predata = 6,
224d865fc92SAndy Fiddaman 		.bufsize = 0,
225d865fc92SAndy Fiddaman 		.x_controllen = 36,
226d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
227d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
228d865fc92SAndy Fiddaman 	},
229d865fc92SAndy Fiddaman 	{
230d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 5",
231d865fc92SAndy Fiddaman 		.send = 2,
232d865fc92SAndy Fiddaman 		.recv = 1,
233d865fc92SAndy Fiddaman 		.predata = 5,
234d865fc92SAndy Fiddaman 		.bufsize = 0,
235d865fc92SAndy Fiddaman 		.x_controllen = 36,
236d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
237d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
238d865fc92SAndy Fiddaman 	},
239d865fc92SAndy Fiddaman 	{
240d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 4",
241d865fc92SAndy Fiddaman 		.send = 2,
242d865fc92SAndy Fiddaman 		.recv = 1,
243d865fc92SAndy Fiddaman 		.predata = 4,
244d865fc92SAndy Fiddaman 		.bufsize = 0,
245d865fc92SAndy Fiddaman 		.x_controllen = 32,
246d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
247d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
248d865fc92SAndy Fiddaman 	},
249d865fc92SAndy Fiddaman 	{
250d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 3",
251d865fc92SAndy Fiddaman 		.send = 2,
252d865fc92SAndy Fiddaman 		.recv = 1,
253d865fc92SAndy Fiddaman 		.predata = 3,
254d865fc92SAndy Fiddaman 		.bufsize = 0,
255d865fc92SAndy Fiddaman 		.x_controllen = 32,
256d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
257d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
258d865fc92SAndy Fiddaman 	},
259d865fc92SAndy Fiddaman 	{
260d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 2",
261d865fc92SAndy Fiddaman 		.send = 2,
262d865fc92SAndy Fiddaman 		.recv = 1,
263d865fc92SAndy Fiddaman 		.predata = 2,
264d865fc92SAndy Fiddaman 		.bufsize = 0,
265d865fc92SAndy Fiddaman 		.x_controllen = 32,
266d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
267d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
268d865fc92SAndy Fiddaman 	},
269d865fc92SAndy Fiddaman 	{
270d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 1",
271d865fc92SAndy Fiddaman 		.send = 2,
272d865fc92SAndy Fiddaman 		.recv = 1,
273d865fc92SAndy Fiddaman 		.predata = 1,
274d865fc92SAndy Fiddaman 		.bufsize = 0,
275d865fc92SAndy Fiddaman 		.x_controllen = 32,
276d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
277d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
278d865fc92SAndy Fiddaman 	},
279d865fc92SAndy Fiddaman 
280d865fc92SAndy Fiddaman 	{
281d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 8, buffer 5",
282d865fc92SAndy Fiddaman 		.send = 2,
283d865fc92SAndy Fiddaman 		.recv = 1,
284d865fc92SAndy Fiddaman 		.predata = 8,
285d865fc92SAndy Fiddaman 		.bufsize = sizeof (int) * 2 - 3,
286d865fc92SAndy Fiddaman 		.x_controllen = 37,
287d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
288d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
289d865fc92SAndy Fiddaman 	},
290d865fc92SAndy Fiddaman 	{
291d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 8, buffer 6",
292d865fc92SAndy Fiddaman 		.send = 2,
293d865fc92SAndy Fiddaman 		.recv = 1,
294d865fc92SAndy Fiddaman 		.predata = 8,
295d865fc92SAndy Fiddaman 		.bufsize = sizeof (int) * 2 - 2,
296d865fc92SAndy Fiddaman 		.x_controllen = 38,
297d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
298d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
299d865fc92SAndy Fiddaman 	},
300d865fc92SAndy Fiddaman 	{
301d865fc92SAndy Fiddaman 		.name = "send 2, recv 1, pre 8, buffer 7",
302d865fc92SAndy Fiddaman 		.send = 2,
303d865fc92SAndy Fiddaman 		.recv = 1,
304d865fc92SAndy Fiddaman 		.predata = 8,
305d865fc92SAndy Fiddaman 		.bufsize = sizeof (int) * 2 - 1,
306d865fc92SAndy Fiddaman 		.x_controllen = 39,
307d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 8,
308d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
309d865fc92SAndy Fiddaman 	},
310d865fc92SAndy Fiddaman 	{
311d865fc92SAndy Fiddaman 		.name = "send 10, recv 1, pre 8",
312d865fc92SAndy Fiddaman 		.send = 10,
313d865fc92SAndy Fiddaman 		.recv = 1,
314d865fc92SAndy Fiddaman 		.predata = 8,
315d865fc92SAndy Fiddaman 		.bufsize = 0,
316d865fc92SAndy Fiddaman 		.x_controllen = 36,
317d865fc92SAndy Fiddaman 		.x_cmsg_datalen = 24,
318d865fc92SAndy Fiddaman 		.x_flags = MSG_CTRUNC,
319d865fc92SAndy Fiddaman 	},
320d865fc92SAndy Fiddaman 
321d865fc92SAndy Fiddaman 	/* End of tests */
322d865fc92SAndy Fiddaman 
323d865fc92SAndy Fiddaman 	{
324d865fc92SAndy Fiddaman 		.name = NULL
325d865fc92SAndy Fiddaman 	}
326d865fc92SAndy Fiddaman };
327d865fc92SAndy Fiddaman 
328d865fc92SAndy Fiddaman static int sock = -1, testfd = -1, cfd = -1;
329d865fc92SAndy Fiddaman static int fdcount;
330d865fc92SAndy Fiddaman 
331d865fc92SAndy Fiddaman static int
fdwalkcb(const prfdinfo_t * info,void * arg)332d865fc92SAndy Fiddaman fdwalkcb(const prfdinfo_t *info, void *arg)
333d865fc92SAndy Fiddaman {
334d865fc92SAndy Fiddaman 	if (!S_ISDIR(info->pr_mode) && info->pr_fd > 2 &&
335d865fc92SAndy Fiddaman 	    info->pr_fd != sock && info->pr_fd != testfd &&
336d865fc92SAndy Fiddaman 	    info->pr_fd != cfd) {
337d865fc92SAndy Fiddaman 		if (debug) {
338d865fc92SAndy Fiddaman 			fprintf(stderr, "%s: unexpected fd: %d\n",
339d865fc92SAndy Fiddaman 			    (char *)arg, info->pr_fd);
340d865fc92SAndy Fiddaman 		}
341d865fc92SAndy Fiddaman 		fdcount++;
342d865fc92SAndy Fiddaman 	}
343d865fc92SAndy Fiddaman 
344d865fc92SAndy Fiddaman 	return (0);
345d865fc92SAndy Fiddaman 
346d865fc92SAndy Fiddaman }
347d865fc92SAndy Fiddaman 
348d865fc92SAndy Fiddaman static void
check_fds(char * tag)349d865fc92SAndy Fiddaman check_fds(char *tag)
350d865fc92SAndy Fiddaman {
351d865fc92SAndy Fiddaman 	fdcount = 0;
352d865fc92SAndy Fiddaman 	proc_fdwalk(getpid(), fdwalkcb, tag);
353d865fc92SAndy Fiddaman }
354d865fc92SAndy Fiddaman 
355d865fc92SAndy Fiddaman static void
send_and_wait(pid_t pid,sigset_t * set,int osig,int isig)356d865fc92SAndy Fiddaman send_and_wait(pid_t pid, sigset_t *set, int osig, int isig)
357d865fc92SAndy Fiddaman {
358d865fc92SAndy Fiddaman 	int sig;
359d865fc92SAndy Fiddaman 
360d865fc92SAndy Fiddaman 	if (osig > 0)
361d865fc92SAndy Fiddaman 		kill(pid, osig);
362d865fc92SAndy Fiddaman 
363d865fc92SAndy Fiddaman 	if (isig > 0) {
364d865fc92SAndy Fiddaman 		if (sigwait(set, &sig) != 0) {
365d865fc92SAndy Fiddaman 			err(EXIT_FAILURE,
366d865fc92SAndy Fiddaman 			    "sigwait failed waiting for %d", isig);
367d865fc92SAndy Fiddaman 		}
368d865fc92SAndy Fiddaman 		if (sig == SIGINT) {
369d865fc92SAndy Fiddaman 			exit(1);
370d865fc92SAndy Fiddaman 		}
371d865fc92SAndy Fiddaman 		if (sig != isig) {
372d865fc92SAndy Fiddaman 			err(EXIT_FAILURE,
373d865fc92SAndy Fiddaman 			    "sigwait returned unexpected signal %d", sig);
374d865fc92SAndy Fiddaman 		}
375d865fc92SAndy Fiddaman 	}
376d865fc92SAndy Fiddaman }
377d865fc92SAndy Fiddaman 
378d865fc92SAndy Fiddaman static void
sendtest(cmsg_test_t * t)379d865fc92SAndy Fiddaman sendtest(cmsg_test_t *t)
380d865fc92SAndy Fiddaman {
381d865fc92SAndy Fiddaman 	struct msghdr msg;
382d865fc92SAndy Fiddaman 	struct cmsghdr *cm;
383d865fc92SAndy Fiddaman 	struct iovec iov;
384d865fc92SAndy Fiddaman 	ssize_t nbytes;
385d865fc92SAndy Fiddaman 	char c = '*';
386d865fc92SAndy Fiddaman 	int i, *p;
387d865fc92SAndy Fiddaman 
388d865fc92SAndy Fiddaman 	bzero(&msg, sizeof (msg));
389d865fc92SAndy Fiddaman 
390d865fc92SAndy Fiddaman 	msg.msg_name = NULL;
391d865fc92SAndy Fiddaman 	msg.msg_namelen = 0;
392d865fc92SAndy Fiddaman 
393d865fc92SAndy Fiddaman 	iov.iov_base = &c;
394d865fc92SAndy Fiddaman 	iov.iov_len = sizeof (c);
395d865fc92SAndy Fiddaman 	msg.msg_iov = &iov;
396d865fc92SAndy Fiddaman 	msg.msg_iovlen = 1;
397d865fc92SAndy Fiddaman 
398d865fc92SAndy Fiddaman 	msg.msg_flags = 0;
399d865fc92SAndy Fiddaman 
400d865fc92SAndy Fiddaman 	msg.msg_controllen = CMSG_SPACE(sizeof (int) * t->send);
401d865fc92SAndy Fiddaman 
402d865fc92SAndy Fiddaman 	if (t->predata > 0) {
403d865fc92SAndy Fiddaman 		/* A dummy cmsg will be inserted at the head of the data */
404d865fc92SAndy Fiddaman 		msg.msg_controllen += CMSG_SPACE(t->predata);
405d865fc92SAndy Fiddaman 	}
406d865fc92SAndy Fiddaman 
407d865fc92SAndy Fiddaman 	msg.msg_control = alloca(msg.msg_controllen);
408d865fc92SAndy Fiddaman 	bzero(msg.msg_control, msg.msg_controllen);
409d865fc92SAndy Fiddaman 
410d865fc92SAndy Fiddaman 	cm = CMSG_FIRSTHDR(&msg);
411d865fc92SAndy Fiddaman 
412d865fc92SAndy Fiddaman 	if (t->predata > 0) {
413d865fc92SAndy Fiddaman 		/* Insert the dummy cmsg */
414d865fc92SAndy Fiddaman 		cm->cmsg_len = CMSG_LEN(t->predata);
415d865fc92SAndy Fiddaman 		cm->cmsg_level = SOL_SOCKET;
416d865fc92SAndy Fiddaman 		cm->cmsg_type = 0;
417d865fc92SAndy Fiddaman 		cm = CMSG_NXTHDR(&msg, cm);
418d865fc92SAndy Fiddaman 	}
419d865fc92SAndy Fiddaman 
420d865fc92SAndy Fiddaman 	cm->cmsg_len = CMSG_LEN(sizeof (int) * t->send);
421d865fc92SAndy Fiddaman 	cm->cmsg_level = SOL_SOCKET;
422d865fc92SAndy Fiddaman 	cm->cmsg_type = SCM_RIGHTS;
423d865fc92SAndy Fiddaman 
424d865fc92SAndy Fiddaman 	p = (int *)CMSG_DATA(cm);
425d865fc92SAndy Fiddaman 	for (i = 0; i < t->send; i++) {
426d865fc92SAndy Fiddaman 		int s = dup(testfd);
427d865fc92SAndy Fiddaman 		if (s == -1)
428d865fc92SAndy Fiddaman 			err(EXIT_FAILURE, "dup()");
429d865fc92SAndy Fiddaman 		*p++ = s;
430d865fc92SAndy Fiddaman 	}
431d865fc92SAndy Fiddaman 
432d865fc92SAndy Fiddaman 	if (debug)
433d865fc92SAndy Fiddaman 		printf("Sending: controllen=%u\n", msg.msg_controllen);
434d865fc92SAndy Fiddaman 
435d865fc92SAndy Fiddaman 	nbytes = sendmsg(cfd, &msg, 0);
436d865fc92SAndy Fiddaman 	if (nbytes == -1)
437d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "sendmsg()");
438d865fc92SAndy Fiddaman 
439d865fc92SAndy Fiddaman 	p = (int *)CMSG_DATA(cm);
440d865fc92SAndy Fiddaman 	for (i = 0; i < t->send; i++)
441d865fc92SAndy Fiddaman 		(void) close(*p++);
442d865fc92SAndy Fiddaman }
443d865fc92SAndy Fiddaman 
444d865fc92SAndy Fiddaman static int
server(const char * sockpath,pid_t pid)445d865fc92SAndy Fiddaman server(const char *sockpath, pid_t pid)
446d865fc92SAndy Fiddaman {
447d865fc92SAndy Fiddaman 	struct sockaddr_un addr;
448d865fc92SAndy Fiddaman 	sigset_t set;
449d865fc92SAndy Fiddaman 	cmsg_test_t *t;
450d865fc92SAndy Fiddaman 
451d865fc92SAndy Fiddaman 	sigemptyset(&set);
452d865fc92SAndy Fiddaman 	sigaddset(&set, SIGUSR2);
453d865fc92SAndy Fiddaman 	sigaddset(&set, SIGINT);
454d865fc92SAndy Fiddaman 
455d865fc92SAndy Fiddaman 	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
456d865fc92SAndy Fiddaman 	if (sock == -1)
457d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "failed to create socket");
458d865fc92SAndy Fiddaman 	addr.sun_family = AF_UNIX;
459d865fc92SAndy Fiddaman 	strlcpy(addr.sun_path, sockpath, sizeof (addr.sun_path));
460d865fc92SAndy Fiddaman 	if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) == -1)
461d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "bind failed");
462d865fc92SAndy Fiddaman 	if (listen(sock, 0) == -1)
463d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "listen failed");
464d865fc92SAndy Fiddaman 
465d865fc92SAndy Fiddaman 	if ((testfd = open("/dev/null", O_RDONLY)) == -1)
466d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "/dev/null");
467d865fc92SAndy Fiddaman 
468d865fc92SAndy Fiddaman 	check_fds("server");
469d865fc92SAndy Fiddaman 
470d865fc92SAndy Fiddaman 	/* Signal the child to connect to the socket */
471d865fc92SAndy Fiddaman 	send_and_wait(pid, &set, SIGUSR1, SIGUSR2);
472d865fc92SAndy Fiddaman 
473d865fc92SAndy Fiddaman 	if ((cfd = accept(sock, NULL, 0)) == -1)
474d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "accept failed");
475d865fc92SAndy Fiddaman 
476d865fc92SAndy Fiddaman 	for (t = tests; t->name != NULL; t++) {
477d865fc92SAndy Fiddaman 		if (debug)
478d865fc92SAndy Fiddaman 			printf("\n>>> Starting test %s\n", t->name);
479d865fc92SAndy Fiddaman 
480d865fc92SAndy Fiddaman 		sendtest(t);
481d865fc92SAndy Fiddaman 		check_fds("server");
482d865fc92SAndy Fiddaman 
483d865fc92SAndy Fiddaman 		send_and_wait(pid, &set, SIGUSR1, SIGUSR2);
484d865fc92SAndy Fiddaman 	}
485d865fc92SAndy Fiddaman 
486d865fc92SAndy Fiddaman 	close(cfd);
487d865fc92SAndy Fiddaman 	close(testfd);
488d865fc92SAndy Fiddaman 	close(sock);
489d865fc92SAndy Fiddaman 
490d865fc92SAndy Fiddaman 	return (0);
491d865fc92SAndy Fiddaman }
492d865fc92SAndy Fiddaman 
493d865fc92SAndy Fiddaman static boolean_t pass;
494d865fc92SAndy Fiddaman 
495d865fc92SAndy Fiddaman static void
check(uint_t actual,uint_t expected,char * tag)496d865fc92SAndy Fiddaman check(uint_t actual, uint_t expected, char *tag)
497d865fc92SAndy Fiddaman {
498d865fc92SAndy Fiddaman 	if (actual != expected) {
499d865fc92SAndy Fiddaman 		fprintf(stderr, "    !!!: "
500d865fc92SAndy Fiddaman 		    "%1$s = %2$u(%2$#x) (expected %3$u(%3$#x))\n",
501d865fc92SAndy Fiddaman 		    tag, actual, expected);
502d865fc92SAndy Fiddaman 		pass = _B_FALSE;
503d865fc92SAndy Fiddaman 	} else if (debug) {
504d865fc92SAndy Fiddaman 		fprintf(stderr, "       : "
505d865fc92SAndy Fiddaman 		    "%1$s = %2$u(%2$#x)\n",
506d865fc92SAndy Fiddaman 		    tag, actual);
507d865fc92SAndy Fiddaman 	}
508d865fc92SAndy Fiddaman }
509d865fc92SAndy Fiddaman 
510d865fc92SAndy Fiddaman static boolean_t
recvtest(cmsg_test_t * t)511d865fc92SAndy Fiddaman recvtest(cmsg_test_t *t)
512d865fc92SAndy Fiddaman {
513d865fc92SAndy Fiddaman 	struct msghdr msg;
514d865fc92SAndy Fiddaman 	struct cmsghdr *cm;
515d865fc92SAndy Fiddaman 	struct iovec iov;
516d865fc92SAndy Fiddaman 	size_t bufsize;
517d865fc92SAndy Fiddaman 	ssize_t nbytes;
518d865fc92SAndy Fiddaman 	char c = '*';
519d865fc92SAndy Fiddaman 
520d865fc92SAndy Fiddaman 	bzero(&msg, sizeof (msg));
521d865fc92SAndy Fiddaman 
522d865fc92SAndy Fiddaman 	msg.msg_name = NULL;
523d865fc92SAndy Fiddaman 	msg.msg_namelen = 0;
524d865fc92SAndy Fiddaman 
525d865fc92SAndy Fiddaman 	iov.iov_base = &c;
526d865fc92SAndy Fiddaman 	iov.iov_len = sizeof (c);
527d865fc92SAndy Fiddaman 	msg.msg_iov = &iov;
528d865fc92SAndy Fiddaman 	msg.msg_iovlen = 1;
529d865fc92SAndy Fiddaman 
530d865fc92SAndy Fiddaman 	msg.msg_flags = 0;
531d865fc92SAndy Fiddaman 
532d865fc92SAndy Fiddaman 	/*
533d865fc92SAndy Fiddaman 	 * If the test does not specify a receive buffer size, calculate one
534d865fc92SAndy Fiddaman 	 * from the number of file descriptors to receive.
535d865fc92SAndy Fiddaman 	 */
536d865fc92SAndy Fiddaman 	if (t->bufsize == 0) {
537d865fc92SAndy Fiddaman 		bufsize = sizeof (int) * t->recv;
538d865fc92SAndy Fiddaman 		bufsize = CMSG_SPACE(bufsize);
539d865fc92SAndy Fiddaman 	} else {
540d865fc92SAndy Fiddaman 		/*
541d865fc92SAndy Fiddaman 		 * Use the specific buffer size provided but add in
542d865fc92SAndy Fiddaman 		 * space for the header
543d865fc92SAndy Fiddaman 		 */
544d865fc92SAndy Fiddaman 		bufsize = t->bufsize + CMSG_LEN(0);
545d865fc92SAndy Fiddaman 	}
546d865fc92SAndy Fiddaman 
547d865fc92SAndy Fiddaman 	if (t->predata > 0) {
548d865fc92SAndy Fiddaman 		/* A dummy cmsg will be found at the head of the data */
549d865fc92SAndy Fiddaman 		bufsize += CMSG_SPACE(t->predata);
550d865fc92SAndy Fiddaman 	}
551d865fc92SAndy Fiddaman 
552d865fc92SAndy Fiddaman 	msg.msg_controllen = bufsize;
553d865fc92SAndy Fiddaman 	msg.msg_control = alloca(bufsize);
554d865fc92SAndy Fiddaman 	bzero(msg.msg_control, msg.msg_controllen);
555d865fc92SAndy Fiddaman 
556d865fc92SAndy Fiddaman 	pass = _B_TRUE;
557d865fc92SAndy Fiddaman 
558d865fc92SAndy Fiddaman 	if (debug)
559d865fc92SAndy Fiddaman 		printf("Receiving: controllen=%u, \n", msg.msg_controllen);
560d865fc92SAndy Fiddaman 
561d865fc92SAndy Fiddaman 	nbytes = recvmsg(sock, &msg, 0);
562d865fc92SAndy Fiddaman 
563d865fc92SAndy Fiddaman 	if (nbytes == -1) {
564d865fc92SAndy Fiddaman 		pass = _B_FALSE;
565d865fc92SAndy Fiddaman 		fprintf(stderr, "recvmsg() failed: %s\n", strerror(errno));
566d865fc92SAndy Fiddaman 		goto out;
567d865fc92SAndy Fiddaman 	}
568d865fc92SAndy Fiddaman 
569d865fc92SAndy Fiddaman 	if (debug) {
570d865fc92SAndy Fiddaman 		printf("Received: controllen=%u, flags=%#x\n",
571d865fc92SAndy Fiddaman 		    msg.msg_controllen, msg.msg_flags);
572d865fc92SAndy Fiddaman 	}
573d865fc92SAndy Fiddaman 
574d865fc92SAndy Fiddaman 	check(msg.msg_flags, t->x_flags, "msg_flags");
575d865fc92SAndy Fiddaman 	check(msg.msg_controllen, t->x_controllen, "msg_controllen");
576d865fc92SAndy Fiddaman 
577d865fc92SAndy Fiddaman 	for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
578d865fc92SAndy Fiddaman 		void *data, *end;
579d865fc92SAndy Fiddaman 
580d865fc92SAndy Fiddaman 		if (debug) {
581d865fc92SAndy Fiddaman 			printf("    >> : Got cmsg %x/%x - %u\n", cm->cmsg_level,
582d865fc92SAndy Fiddaman 			    cm->cmsg_type, cm->cmsg_len);
583d865fc92SAndy Fiddaman 		}
584d865fc92SAndy Fiddaman 
585d865fc92SAndy Fiddaman 		if (cm->cmsg_type != SCM_RIGHTS) {
586d865fc92SAndy Fiddaman 			if (debug)
587d865fc92SAndy Fiddaman 				printf("       : skipping cmsg\n");
588d865fc92SAndy Fiddaman 			continue;
589d865fc92SAndy Fiddaman 		}
590d865fc92SAndy Fiddaman 
591d865fc92SAndy Fiddaman 		check(cm->cmsg_len - CMSG_LEN(0),
592d865fc92SAndy Fiddaman 		    t->x_cmsg_datalen, "cmsg_len");
593d865fc92SAndy Fiddaman 
594d865fc92SAndy Fiddaman 		/* Close any received file descriptors */
595d865fc92SAndy Fiddaman 		data = CMSG_DATA(cm);
596d865fc92SAndy Fiddaman 
597d865fc92SAndy Fiddaman 		if ((msg.msg_flags & MSG_CTRUNC) &&
598d865fc92SAndy Fiddaman 		    CMSG_NXTHDR(&msg, cm) == NULL) {
599d865fc92SAndy Fiddaman 			/*
600d865fc92SAndy Fiddaman 			 * illumos did not previously adjust cmsg_len on
601d865fc92SAndy Fiddaman 			 * truncation. This is the last cmsg, derive the
602d865fc92SAndy Fiddaman 			 * length from msg_controllen
603d865fc92SAndy Fiddaman 			 */
604d865fc92SAndy Fiddaman 			end = msg.msg_control + msg.msg_controllen;
605d865fc92SAndy Fiddaman 		} else {
606d865fc92SAndy Fiddaman 			end = data + cm->cmsg_len - CMSG_LEN(0);
607d865fc92SAndy Fiddaman 		}
608d865fc92SAndy Fiddaman 
609d865fc92SAndy Fiddaman 		while (data <= end - sizeof (int)) {
610d865fc92SAndy Fiddaman 			int *a = (int *)data;
611d865fc92SAndy Fiddaman 			if (debug)
612d865fc92SAndy Fiddaman 				printf("       : close(%d)\n", *a);
613d865fc92SAndy Fiddaman 			if (close(*a) == -1) {
614d865fc92SAndy Fiddaman 				pass = _B_FALSE;
615d865fc92SAndy Fiddaman 				fprintf(stderr, "    !!!: "
616d865fc92SAndy Fiddaman 				    "failed to close fd %d - %s\n", *a,
617d865fc92SAndy Fiddaman 				    strerror(errno));
618d865fc92SAndy Fiddaman 			}
619d865fc92SAndy Fiddaman 			data += sizeof (int);
620d865fc92SAndy Fiddaman 		}
621d865fc92SAndy Fiddaman 	}
622d865fc92SAndy Fiddaman 
623d865fc92SAndy Fiddaman out:
624d865fc92SAndy Fiddaman 
625d865fc92SAndy Fiddaman 	check_fds("client");
626d865fc92SAndy Fiddaman 	check(fdcount, 0, "client descriptors");
627d865fc92SAndy Fiddaman 	printf("     + : %s %s\n", pass ? "PASS" : "FAIL", t->name);
628d865fc92SAndy Fiddaman 
629d865fc92SAndy Fiddaman 	return (pass);
630d865fc92SAndy Fiddaman }
631d865fc92SAndy Fiddaman 
632d865fc92SAndy Fiddaman static int
client(const char * sockpath,pid_t pid)633d865fc92SAndy Fiddaman client(const char *sockpath, pid_t pid)
634d865fc92SAndy Fiddaman {
635d865fc92SAndy Fiddaman 	struct sockaddr_un addr;
636d865fc92SAndy Fiddaman 	sigset_t set;
637d865fc92SAndy Fiddaman 	cmsg_test_t *t;
638d865fc92SAndy Fiddaman 	int ret = 0;
639d865fc92SAndy Fiddaman 
640d865fc92SAndy Fiddaman 	sigemptyset(&set);
641d865fc92SAndy Fiddaman 	sigaddset(&set, SIGUSR1);
642d865fc92SAndy Fiddaman 	sigaddset(&set, SIGINT);
643d865fc92SAndy Fiddaman 
644d865fc92SAndy Fiddaman 	send_and_wait(pid, &set, 0, SIGUSR1);
645d865fc92SAndy Fiddaman 
646d865fc92SAndy Fiddaman 	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
647d865fc92SAndy Fiddaman 	if (sock == -1)
648d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "failed to create socket");
649d865fc92SAndy Fiddaman 	addr.sun_family = AF_UNIX;
650d865fc92SAndy Fiddaman 	strlcpy(addr.sun_path, sockpath, sizeof (addr.sun_path));
651d865fc92SAndy Fiddaman 	if (connect(sock, (struct sockaddr *)&addr, sizeof (addr)) == -1)
652d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "could not connect to server socket");
653d865fc92SAndy Fiddaman 
654d865fc92SAndy Fiddaman 	for (t = tests; t->name != NULL; t++) {
655d865fc92SAndy Fiddaman 		send_and_wait(pid, &set, SIGUSR2, SIGUSR1);
656d865fc92SAndy Fiddaman 		if (!recvtest(t))
657d865fc92SAndy Fiddaman 			ret = 1;
658d865fc92SAndy Fiddaman 	}
659d865fc92SAndy Fiddaman 
660d865fc92SAndy Fiddaman 	close(sock);
661d865fc92SAndy Fiddaman 
662d865fc92SAndy Fiddaman 	return (ret);
663d865fc92SAndy Fiddaman }
664d865fc92SAndy Fiddaman 
665d865fc92SAndy Fiddaman int
main(int argc,const char ** argv)666d865fc92SAndy Fiddaman main(int argc, const char **argv)
667d865fc92SAndy Fiddaman {
668d865fc92SAndy Fiddaman 	char sockpath[] = "/tmp/cmsg.testsock.XXXXXX";
669d865fc92SAndy Fiddaman 	pid_t pid, ppid;
670d865fc92SAndy Fiddaman 	sigset_t set;
671d865fc92SAndy Fiddaman 	int ret = 0;
672d865fc92SAndy Fiddaman 
673*480497bcSJason King 	/*
674*480497bcSJason King 	 * The tests make assumptions about the number of open file descriptors
675*480497bcSJason King 	 * present. In case we are invoked with more than just STDIN_FILENO,
676*480497bcSJason King 	 * STDOUT_FILENO, and STDERR_FILENO open, close any other open
677*480497bcSJason King 	 * descriptors that might exist. Otherwise their presence will violate
678*480497bcSJason King 	 * the assumptions of the test and cause an erroneous failure.
679*480497bcSJason King 	 */
680*480497bcSJason King 	closefrom(STDERR_FILENO + 1);
681*480497bcSJason King 
682d865fc92SAndy Fiddaman 	if (argc > 1 && strcmp(argv[1], "-d") == 0)
683d865fc92SAndy Fiddaman 		debug = _B_TRUE;
684d865fc92SAndy Fiddaman 
685d865fc92SAndy Fiddaman 	sigfillset(&set);
686d865fc92SAndy Fiddaman 	sigdelset(&set, SIGINT);
687d865fc92SAndy Fiddaman 	sigdelset(&set, SIGTSTP);
688d865fc92SAndy Fiddaman 	sigprocmask(SIG_BLOCK, &set, NULL);
689d865fc92SAndy Fiddaman 
690d865fc92SAndy Fiddaman 	if (mktemp(sockpath) == NULL)
691d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "Failed to make temporary socket path");
692d865fc92SAndy Fiddaman 
693d865fc92SAndy Fiddaman 	ppid = getpid();
694d865fc92SAndy Fiddaman 	pid = fork();
695d865fc92SAndy Fiddaman 	switch (pid) {
696d865fc92SAndy Fiddaman 	case -1:
697d865fc92SAndy Fiddaman 		err(EXIT_FAILURE, "fork failed");
698d865fc92SAndy Fiddaman 	case 0:
699d865fc92SAndy Fiddaman 		return (server(sockpath, ppid));
700d865fc92SAndy Fiddaman 	default:
701d865fc92SAndy Fiddaman 		break;
702d865fc92SAndy Fiddaman 	}
703d865fc92SAndy Fiddaman 
704d865fc92SAndy Fiddaman 	ret = client(sockpath, pid);
705d865fc92SAndy Fiddaman 	kill(pid, SIGINT);
706d865fc92SAndy Fiddaman 
707d865fc92SAndy Fiddaman 	unlink(sockpath);
708d865fc92SAndy Fiddaman 
709d865fc92SAndy Fiddaman 	return (ret);
710d865fc92SAndy Fiddaman }
711