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