1/* Smoke test for MSG_CMSG_CLOEXEC.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
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.
9
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.
14
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/>. */
18
19#include <support/xunistd.h>
20#include <support/check.h>
21#include <sys/socket.h>
22#include <sys/un.h>
23#include <string.h>
24#include <fcntl.h>
25
26static void
27send_fd (int sockfd, int fd)
28{
29 char data[] = "hello";
30 struct iovec iov = { .iov_base = data, .iov_len = sizeof (data) };
31
32 union
33 {
34 struct cmsghdr header;
35 char bytes[CMSG_SPACE (sizeof (fd))];
36 } cmsg_storage;
37
38 struct msghdr msg =
39 {
40 .msg_iov = &iov,
41 .msg_iovlen = 1,
42 .msg_control = cmsg_storage.bytes,
43 .msg_controllen = sizeof (cmsg_storage)
44 };
45
46 memset (&cmsg_storage, 0, sizeof (cmsg_storage));
47
48 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
49 cmsg->cmsg_level = SOL_SOCKET;
50 cmsg->cmsg_type = SCM_RIGHTS;
51 cmsg->cmsg_len = CMSG_LEN (sizeof (fd));
52 memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd));
53
54 ssize_t nsent = sendmsg (fd: sockfd, message: &msg, flags: 0);
55 if (nsent < 0)
56 FAIL_EXIT1 ("sendmsg (%d): %m", sockfd);
57 TEST_COMPARE (nsent, sizeof (data));
58}
59
60static int
61recv_fd (int sockfd, int flags)
62{
63 char buffer[100];
64 struct iovec iov = { .iov_base = buffer, .iov_len = sizeof (buffer) };
65
66 union
67 {
68 struct cmsghdr header;
69 char bytes[100];
70 } cmsg_storage;
71
72 struct msghdr msg =
73 {
74 .msg_iov = &iov,
75 .msg_iovlen = 1,
76 .msg_control = cmsg_storage.bytes,
77 .msg_controllen = sizeof (cmsg_storage)
78 };
79
80 ssize_t nrecv = recvmsg (fd: sockfd, message: &msg, flags: flags);
81 if (nrecv < 0)
82 FAIL_EXIT1 ("recvmsg (%d): %m", sockfd);
83
84 TEST_COMPARE (msg.msg_controllen, CMSG_SPACE (sizeof (int)));
85 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
86 TEST_COMPARE (cmsg->cmsg_level, SOL_SOCKET);
87 TEST_COMPARE (cmsg->cmsg_type, SCM_RIGHTS);
88 TEST_COMPARE (cmsg->cmsg_len, CMSG_LEN (sizeof (int)));
89
90 int fd;
91 memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd));
92 return fd;
93}
94
95static int
96do_test (void)
97{
98 int sockfd[2];
99 int newfd;
100 int flags;
101 int rc = socketpair (AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, protocol: 0, fds: sockfd);
102 if (rc < 0)
103 FAIL_EXIT1 ("socketpair: %m");
104
105 send_fd (sockfd: sockfd[1], STDIN_FILENO);
106 newfd = recv_fd (sockfd: sockfd[0], flags: 0);
107 TEST_VERIFY_EXIT (newfd > 0);
108 flags = fcntl (fd: newfd, F_GETFD, 0);
109 TEST_VERIFY_EXIT (flags != -1);
110 TEST_VERIFY (!(flags & FD_CLOEXEC));
111 xclose (newfd);
112
113 send_fd (sockfd: sockfd[1], STDIN_FILENO);
114 newfd = recv_fd (sockfd: sockfd[0], MSG_CMSG_CLOEXEC);
115 TEST_VERIFY_EXIT (newfd > 0);
116 flags = fcntl (fd: newfd, F_GETFD, 0);
117 TEST_VERIFY_EXIT (flags != -1);
118 TEST_VERIFY (flags & FD_CLOEXEC);
119 xclose (newfd);
120
121 xclose (sockfd[0]);
122 xclose (sockfd[1]);
123 return 0;
124}
125
126#include <support/test-driver.c>
127

source code of glibc/socket/tst-cmsg_cloexec.c