xref: /aosp_15_r20/external/wayland/src/wayland-os.c (revision 84e872a0dc482bffdb63672969dd03a827d67c73)
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