1 /* Smoke test for SCM_RIGHTS.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 /* This test passes a file descriptor from a subprocess to the parent
20 process, using recvmsg/sendmsg or recvmmsg/sendmmsg. */
26 #include <support/check.h>
27 #include <support/xunistd.h>
28 #include <sys/socket.h>
32 /* String sent over the socket. */
33 static char DATA
[] = "descriptor";
35 /* Path that is to be opened and sent over the socket. */
38 /* True if sendmmsg/recvmmsg is to be used. */
39 static bool use_multi_call
;
41 /* The pair of sockets used for coordination. The subprocess uses
43 static int sockets
[2];
45 /* Subprocess side of one send/receive test. */
49 /* The file descriptor to send. */
50 int fd
= xopen (PATH
, O_RDONLY
, 0);
52 struct iovec iov
= { .iov_base
= DATA
, .iov_len
= sizeof (DATA
) };
55 struct cmsghdr header
;
56 char bytes
[CMSG_SPACE (sizeof (int))];
58 struct mmsghdr mmhdr
=
64 .msg_control
= cmsg_storage
.bytes
,
65 .msg_controllen
= sizeof (cmsg_storage
),
69 /* Configure the file descriptor for sending. */
70 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR (&mmhdr
.msg_hdr
);
71 cmsg
->cmsg_level
= SOL_SOCKET
;
72 cmsg
->cmsg_type
= SCM_RIGHTS
;
73 cmsg
->cmsg_len
= CMSG_LEN (sizeof (int));
74 memcpy (CMSG_DATA (cmsg
), &fd
, sizeof (fd
));
75 mmhdr
.msg_hdr
.msg_controllen
= cmsg
->cmsg_len
;
77 /* Perform the send operation. */
81 ret
= sendmmsg (sockets
[1], &mmhdr
, 1, 0);
86 ret
= sendmsg (sockets
[1], &mmhdr
.msg_hdr
, 0);
87 TEST_COMPARE (ret
, sizeof (DATA
));
91 /* Stop the process from exiting. */
96 /* Performs one send/receive test. */
100 TEST_COMPARE (socketpair (AF_UNIX
, SOCK_STREAM
, 0, sockets
), 0);
102 pid_t pid
= xfork ();
106 char data_storage
[sizeof (DATA
) + 1];
109 .iov_base
= data_storage
,
110 .iov_len
= sizeof (data_storage
)
114 struct cmsghdr header
;
115 char bytes
[CMSG_SPACE (sizeof (int))];
117 struct mmsghdr mmhdr
=
123 .msg_control
= cmsg_storage
.bytes
,
124 .msg_controllen
= sizeof (cmsg_storage
),
128 /* Set up the space for receiving the file descriptor. */
129 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR (&mmhdr
.msg_hdr
);
130 cmsg
->cmsg_level
= SOL_SOCKET
;
131 cmsg
->cmsg_type
= SCM_RIGHTS
;
132 cmsg
->cmsg_len
= CMSG_LEN (sizeof (int));
133 mmhdr
.msg_hdr
.msg_controllen
= cmsg
->cmsg_len
;
135 /* Perform the receive operation. */
139 ret
= recvmmsg (sockets
[0], &mmhdr
, 1, 0, NULL
);
144 ret
= recvmsg (sockets
[0], &mmhdr
.msg_hdr
, 0);
145 TEST_COMPARE (ret
, sizeof (DATA
));
146 TEST_COMPARE_BLOB (data_storage
, sizeof (DATA
), DATA
, sizeof (DATA
));
148 /* Extract the file descriptor. */
149 TEST_VERIFY (CMSG_FIRSTHDR (&mmhdr
.msg_hdr
) != NULL
);
150 TEST_COMPARE (CMSG_FIRSTHDR (&mmhdr
.msg_hdr
)->cmsg_len
,
151 CMSG_LEN (sizeof (int)));
152 TEST_VERIFY (&cmsg_storage
.header
== CMSG_FIRSTHDR (&mmhdr
.msg_hdr
));
154 memcpy (&fd
, CMSG_DATA (CMSG_FIRSTHDR (&mmhdr
.msg_hdr
)), sizeof (fd
));
156 /* Verify the received file descriptor. */
157 TEST_VERIFY (fd
> 2);
159 TEST_COMPARE (fstat64 (fd
, &st_fd
), 0);
160 struct stat64 st_path
;
161 TEST_COMPARE (stat64 (PATH
, &st_path
), 0);
162 TEST_COMPARE (st_fd
.st_ino
, st_path
.st_ino
);
163 TEST_COMPARE (st_fd
.st_dev
, st_path
.st_dev
);
166 /* Terminate the subprocess. */
167 TEST_COMPARE (kill (pid
, SIGUSR1
), 0);
169 TEST_COMPARE (xwaitpid (pid
, &status
, 0), pid
);
170 TEST_VERIFY (WIFSIGNALED (status
));
171 TEST_COMPARE (WTERMSIG (status
), SIGUSR1
);
181 use_multi_call
= true;
186 #include <support/test-driver.c>