1*84e872a0SLloyd Pique /*
2*84e872a0SLloyd Pique * Copyright © 2012 Collabora, Ltd.
3*84e872a0SLloyd Pique *
4*84e872a0SLloyd Pique * Permission is hereby granted, free of charge, to any person obtaining
5*84e872a0SLloyd Pique * a copy of this software and associated documentation files (the
6*84e872a0SLloyd Pique * "Software"), to deal in the Software without restriction, including
7*84e872a0SLloyd Pique * without limitation the rights to use, copy, modify, merge, publish,
8*84e872a0SLloyd Pique * distribute, sublicense, and/or sell copies of the Software, and to
9*84e872a0SLloyd Pique * permit persons to whom the Software is furnished to do so, subject to
10*84e872a0SLloyd Pique * the following conditions:
11*84e872a0SLloyd Pique *
12*84e872a0SLloyd Pique * The above copyright notice and this permission notice (including the
13*84e872a0SLloyd Pique * next paragraph) shall be included in all copies or substantial
14*84e872a0SLloyd Pique * portions of the Software.
15*84e872a0SLloyd Pique *
16*84e872a0SLloyd Pique * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17*84e872a0SLloyd Pique * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*84e872a0SLloyd Pique * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19*84e872a0SLloyd Pique * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20*84e872a0SLloyd Pique * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21*84e872a0SLloyd Pique * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22*84e872a0SLloyd Pique * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23*84e872a0SLloyd Pique * SOFTWARE.
24*84e872a0SLloyd Pique */
25*84e872a0SLloyd Pique
26*84e872a0SLloyd Pique #define _GNU_SOURCE
27*84e872a0SLloyd Pique
28*84e872a0SLloyd Pique #include "../config.h"
29*84e872a0SLloyd Pique
30*84e872a0SLloyd Pique #include <sys/types.h>
31*84e872a0SLloyd Pique #include <sys/socket.h>
32*84e872a0SLloyd Pique #include <unistd.h>
33*84e872a0SLloyd Pique #include <fcntl.h>
34*84e872a0SLloyd Pique #include <errno.h>
35*84e872a0SLloyd Pique #include <string.h>
36*84e872a0SLloyd Pique #include <sys/epoll.h>
37*84e872a0SLloyd Pique #include <sys/mman.h>
38*84e872a0SLloyd Pique #include <sys/un.h>
39*84e872a0SLloyd Pique #ifdef HAVE_SYS_UCRED_H
40*84e872a0SLloyd Pique #include <sys/ucred.h>
41*84e872a0SLloyd Pique #endif
42*84e872a0SLloyd Pique
43*84e872a0SLloyd Pique #include "wayland-os.h"
44*84e872a0SLloyd Pique
45*84e872a0SLloyd Pique static int
set_cloexec_or_close(int fd)46*84e872a0SLloyd Pique set_cloexec_or_close(int fd)
47*84e872a0SLloyd Pique {
48*84e872a0SLloyd Pique long flags;
49*84e872a0SLloyd Pique
50*84e872a0SLloyd Pique if (fd == -1)
51*84e872a0SLloyd Pique return -1;
52*84e872a0SLloyd Pique
53*84e872a0SLloyd Pique flags = fcntl(fd, F_GETFD);
54*84e872a0SLloyd Pique if (flags == -1)
55*84e872a0SLloyd Pique goto err;
56*84e872a0SLloyd Pique
57*84e872a0SLloyd Pique if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
58*84e872a0SLloyd Pique goto err;
59*84e872a0SLloyd Pique
60*84e872a0SLloyd Pique return fd;
61*84e872a0SLloyd Pique
62*84e872a0SLloyd Pique err:
63*84e872a0SLloyd Pique close(fd);
64*84e872a0SLloyd Pique return -1;
65*84e872a0SLloyd Pique }
66*84e872a0SLloyd Pique
67*84e872a0SLloyd Pique int
wl_os_socket_cloexec(int domain,int type,int protocol)68*84e872a0SLloyd Pique wl_os_socket_cloexec(int domain, int type, int protocol)
69*84e872a0SLloyd Pique {
70*84e872a0SLloyd Pique int fd;
71*84e872a0SLloyd Pique
72*84e872a0SLloyd Pique fd = socket(domain, type | SOCK_CLOEXEC, protocol);
73*84e872a0SLloyd Pique if (fd >= 0)
74*84e872a0SLloyd Pique return fd;
75*84e872a0SLloyd Pique if (errno != EINVAL)
76*84e872a0SLloyd Pique return -1;
77*84e872a0SLloyd Pique
78*84e872a0SLloyd Pique fd = socket(domain, type, protocol);
79*84e872a0SLloyd Pique return set_cloexec_or_close(fd);
80*84e872a0SLloyd Pique }
81*84e872a0SLloyd Pique
82*84e872a0SLloyd Pique #if defined(__FreeBSD__)
83*84e872a0SLloyd Pique int
wl_os_socket_peercred(int sockfd,uid_t * uid,gid_t * gid,pid_t * pid)84*84e872a0SLloyd Pique wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid)
85*84e872a0SLloyd Pique {
86*84e872a0SLloyd Pique socklen_t len;
87*84e872a0SLloyd Pique struct xucred ucred;
88*84e872a0SLloyd Pique
89*84e872a0SLloyd Pique len = sizeof(ucred);
90*84e872a0SLloyd Pique if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &ucred, &len) < 0 ||
91*84e872a0SLloyd Pique ucred.cr_version != XUCRED_VERSION)
92*84e872a0SLloyd Pique return -1;
93*84e872a0SLloyd Pique *uid = ucred.cr_uid;
94*84e872a0SLloyd Pique *gid = ucred.cr_gid;
95*84e872a0SLloyd Pique #if HAVE_XUCRED_CR_PID
96*84e872a0SLloyd Pique /* Since https://cgit.freebsd.org/src/commit/?id=c5afec6e895a */
97*84e872a0SLloyd Pique *pid = ucred.cr_pid;
98*84e872a0SLloyd Pique #else
99*84e872a0SLloyd Pique *pid = 0;
100*84e872a0SLloyd Pique #endif
101*84e872a0SLloyd Pique return 0;
102*84e872a0SLloyd Pique }
103*84e872a0SLloyd Pique #elif defined(SO_PEERCRED)
104*84e872a0SLloyd Pique int
wl_os_socket_peercred(int sockfd,uid_t * uid,gid_t * gid,pid_t * pid)105*84e872a0SLloyd Pique wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid)
106*84e872a0SLloyd Pique {
107*84e872a0SLloyd Pique socklen_t len;
108*84e872a0SLloyd Pique struct ucred ucred;
109*84e872a0SLloyd Pique
110*84e872a0SLloyd Pique len = sizeof(ucred);
111*84e872a0SLloyd Pique if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0)
112*84e872a0SLloyd Pique return -1;
113*84e872a0SLloyd Pique *uid = ucred.uid;
114*84e872a0SLloyd Pique *gid = ucred.gid;
115*84e872a0SLloyd Pique *pid = ucred.pid;
116*84e872a0SLloyd Pique return 0;
117*84e872a0SLloyd Pique }
118*84e872a0SLloyd Pique #else
119*84e872a0SLloyd Pique #error "Don't know how to read ucred on this platform"
120*84e872a0SLloyd Pique #endif
121*84e872a0SLloyd Pique
122*84e872a0SLloyd Pique int
wl_os_dupfd_cloexec(int fd,int minfd)123*84e872a0SLloyd Pique wl_os_dupfd_cloexec(int fd, int minfd)
124*84e872a0SLloyd Pique {
125*84e872a0SLloyd Pique int newfd;
126*84e872a0SLloyd Pique
127*84e872a0SLloyd Pique newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
128*84e872a0SLloyd Pique if (newfd >= 0)
129*84e872a0SLloyd Pique return newfd;
130*84e872a0SLloyd Pique if (errno != EINVAL)
131*84e872a0SLloyd Pique return -1;
132*84e872a0SLloyd Pique
133*84e872a0SLloyd Pique newfd = fcntl(fd, F_DUPFD, minfd);
134*84e872a0SLloyd Pique return set_cloexec_or_close(newfd);
135*84e872a0SLloyd Pique }
136*84e872a0SLloyd Pique
137*84e872a0SLloyd Pique static ssize_t
recvmsg_cloexec_fallback(int sockfd,struct msghdr * msg,int flags)138*84e872a0SLloyd Pique recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
139*84e872a0SLloyd Pique {
140*84e872a0SLloyd Pique ssize_t len;
141*84e872a0SLloyd Pique struct cmsghdr *cmsg;
142*84e872a0SLloyd Pique unsigned char *data;
143*84e872a0SLloyd Pique int *fd;
144*84e872a0SLloyd Pique int *end;
145*84e872a0SLloyd Pique
146*84e872a0SLloyd Pique len = recvmsg(sockfd, msg, flags);
147*84e872a0SLloyd Pique if (len == -1)
148*84e872a0SLloyd Pique return -1;
149*84e872a0SLloyd Pique
150*84e872a0SLloyd Pique if (!msg->msg_control || msg->msg_controllen == 0)
151*84e872a0SLloyd Pique return len;
152*84e872a0SLloyd Pique
153*84e872a0SLloyd Pique cmsg = CMSG_FIRSTHDR(msg);
154*84e872a0SLloyd Pique for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
155*84e872a0SLloyd Pique if (cmsg->cmsg_level != SOL_SOCKET ||
156*84e872a0SLloyd Pique cmsg->cmsg_type != SCM_RIGHTS)
157*84e872a0SLloyd Pique continue;
158*84e872a0SLloyd Pique
159*84e872a0SLloyd Pique data = CMSG_DATA(cmsg);
160*84e872a0SLloyd Pique end = (int *)(data + cmsg->cmsg_len - CMSG_LEN(0));
161*84e872a0SLloyd Pique for (fd = (int *)data; fd < end; ++fd)
162*84e872a0SLloyd Pique *fd = set_cloexec_or_close(*fd);
163*84e872a0SLloyd Pique }
164*84e872a0SLloyd Pique
165*84e872a0SLloyd Pique return len;
166*84e872a0SLloyd Pique }
167*84e872a0SLloyd Pique
168*84e872a0SLloyd Pique ssize_t
wl_os_recvmsg_cloexec(int sockfd,struct msghdr * msg,int flags)169*84e872a0SLloyd Pique wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
170*84e872a0SLloyd Pique {
171*84e872a0SLloyd Pique #if HAVE_BROKEN_MSG_CMSG_CLOEXEC
172*84e872a0SLloyd Pique /*
173*84e872a0SLloyd Pique * FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015
174*84e872a0SLloyd Pique * and 2021, so we have to use the non-MSG_CMSG_CLOEXEC fallback
175*84e872a0SLloyd Pique * directly when compiling against a version that does not include the
176*84e872a0SLloyd Pique * fix (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211).
177*84e872a0SLloyd Pique */
178*84e872a0SLloyd Pique #pragma message("Using fallback directly since MSG_CMSG_CLOEXEC is broken.")
179*84e872a0SLloyd Pique #else
180*84e872a0SLloyd Pique ssize_t len;
181*84e872a0SLloyd Pique
182*84e872a0SLloyd Pique len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
183*84e872a0SLloyd Pique if (len >= 0)
184*84e872a0SLloyd Pique return len;
185*84e872a0SLloyd Pique if (errno != EINVAL)
186*84e872a0SLloyd Pique return -1;
187*84e872a0SLloyd Pique #endif
188*84e872a0SLloyd Pique return recvmsg_cloexec_fallback(sockfd, msg, flags);
189*84e872a0SLloyd Pique }
190*84e872a0SLloyd Pique
191*84e872a0SLloyd Pique int
wl_os_epoll_create_cloexec(void)192*84e872a0SLloyd Pique wl_os_epoll_create_cloexec(void)
193*84e872a0SLloyd Pique {
194*84e872a0SLloyd Pique int fd;
195*84e872a0SLloyd Pique
196*84e872a0SLloyd Pique #ifdef EPOLL_CLOEXEC
197*84e872a0SLloyd Pique fd = epoll_create1(EPOLL_CLOEXEC);
198*84e872a0SLloyd Pique if (fd >= 0)
199*84e872a0SLloyd Pique return fd;
200*84e872a0SLloyd Pique if (errno != EINVAL)
201*84e872a0SLloyd Pique return -1;
202*84e872a0SLloyd Pique #endif
203*84e872a0SLloyd Pique
204*84e872a0SLloyd Pique fd = epoll_create(1);
205*84e872a0SLloyd Pique return set_cloexec_or_close(fd);
206*84e872a0SLloyd Pique }
207*84e872a0SLloyd Pique
208*84e872a0SLloyd Pique int
wl_os_accept_cloexec(int sockfd,struct sockaddr * addr,socklen_t * addrlen)209*84e872a0SLloyd Pique wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
210*84e872a0SLloyd Pique {
211*84e872a0SLloyd Pique int fd;
212*84e872a0SLloyd Pique
213*84e872a0SLloyd Pique #ifdef HAVE_ACCEPT4
214*84e872a0SLloyd Pique fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
215*84e872a0SLloyd Pique if (fd >= 0)
216*84e872a0SLloyd Pique return fd;
217*84e872a0SLloyd Pique if (errno != ENOSYS)
218*84e872a0SLloyd Pique return -1;
219*84e872a0SLloyd Pique #endif
220*84e872a0SLloyd Pique
221*84e872a0SLloyd Pique fd = accept(sockfd, addr, addrlen);
222*84e872a0SLloyd Pique return set_cloexec_or_close(fd);
223*84e872a0SLloyd Pique }
224*84e872a0SLloyd Pique
225*84e872a0SLloyd Pique /*
226*84e872a0SLloyd Pique * Fallback function for operating systems that don't implement
227*84e872a0SLloyd Pique * mremap(MREMAP_MAYMOVE).
228*84e872a0SLloyd Pique */
229*84e872a0SLloyd Pique void *
wl_os_mremap_maymove(int fd,void * old_data,ssize_t * old_size,ssize_t new_size,int prot,int flags)230*84e872a0SLloyd Pique wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size,
231*84e872a0SLloyd Pique ssize_t new_size, int prot, int flags)
232*84e872a0SLloyd Pique {
233*84e872a0SLloyd Pique void *result;
234*84e872a0SLloyd Pique
235*84e872a0SLloyd Pique /* Make sure any pending write is flushed. */
236*84e872a0SLloyd Pique if (msync(old_data, *old_size, MS_SYNC) != 0)
237*84e872a0SLloyd Pique return MAP_FAILED;
238*84e872a0SLloyd Pique
239*84e872a0SLloyd Pique /* We could try mapping a new block immediately after the current one
240*84e872a0SLloyd Pique * with MAP_FIXED, however that is not guaranteed to work and breaks
241*84e872a0SLloyd Pique * on CHERI-enabled architectures since the data pointer will still
242*84e872a0SLloyd Pique * have the bounds of the previous allocation.
243*84e872a0SLloyd Pique */
244*84e872a0SLloyd Pique result = mmap(NULL, new_size, prot, flags, fd, 0);
245*84e872a0SLloyd Pique if (result == MAP_FAILED)
246*84e872a0SLloyd Pique return MAP_FAILED;
247*84e872a0SLloyd Pique
248*84e872a0SLloyd Pique if (munmap(old_data, *old_size) == 0)
249*84e872a0SLloyd Pique *old_size = 0;
250*84e872a0SLloyd Pique
251*84e872a0SLloyd Pique return result;
252*84e872a0SLloyd Pique }
253