FreeRDP
Loading...
Searching...
No Matches
uwac-os.c
1/*
2 * Copyright © 2012 Collabora, Ltd.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23/*
24 * This file is an adaptation of src/wayland-os.h from the wayland project and
25 * shared/os-compatiblity.h from the weston project.
26 *
27 * Functions have been renamed just to prevent name clashes.
28 */
29
30#if defined(__clang__)
31#pragma clang diagnostic push
32#pragma clang diagnostic ignored "-Wreserved-id-macro"
33#endif
34
35#define _GNU_SOURCE // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
36
37#if defined(__clang__)
38#pragma clang diagnostic pop
39#endif
40
41#ifdef __FreeBSD__
42#define USE_SHM
43#endif
44
45#include <sys/types.h>
46#include <sys/socket.h>
47#ifdef USE_SHM
48#include <sys/mman.h>
49#endif
50#include <unistd.h>
51#include <fcntl.h>
52#include <errno.h>
53#include <stdlib.h>
54#include <stdio.h>
55#include <string.h>
56#include <sys/epoll.h>
57#include <sys/stat.h>
58
59#include <winpr/wtypes.h>
60#include <uwac/config.h>
61
62#include "uwac-os.h"
63#include "uwac-utils.h"
64
65static int set_cloexec_or_close(int fd)
66{
67 long flags = 0;
68
69 if (fd == -1)
70 return -1;
71
72 flags = fcntl(fd, F_GETFD);
73
74 if (flags == -1)
75 goto err;
76
77 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
78 goto err;
79
80 return fd;
81err:
82 close(fd);
83 return -1;
84}
85
86int uwac_os_socket_cloexec(int domain, int type, int protocol)
87{
88 int fd = 0;
89 fd = socket(domain, type | SOCK_CLOEXEC, protocol);
90
91 if (fd >= 0)
92 return fd;
93
94 if (errno != EINVAL)
95 return -1;
96
97 fd = socket(domain, type, protocol);
98 return set_cloexec_or_close(fd);
99}
100
101int uwac_os_dupfd_cloexec(int fd, long minfd)
102{
103 int newfd = 0;
104 newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
105
106 if (newfd >= 0)
107 return newfd;
108
109 if (errno != EINVAL)
110 return -1;
111
112 newfd = fcntl(fd, F_DUPFD, minfd);
113 return set_cloexec_or_close(newfd);
114}
115
116static ssize_t recvmsg_cloexec_fallback(int sockfd, struct msghdr* msg, int flags)
117{
118 ssize_t len = 0;
119 struct cmsghdr* cmsg = nullptr;
120 unsigned char* data = nullptr;
121 int* end = nullptr;
122 len = recvmsg(sockfd, msg, flags);
123
124 if (len == -1)
125 return -1;
126
127 if (!msg->msg_control || msg->msg_controllen == 0)
128 return len;
129
130 cmsg = CMSG_FIRSTHDR(msg);
131
132 for (; cmsg != nullptr; cmsg = CMSG_NXTHDR(msg, cmsg))
133 {
134 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
135 continue;
136
137 data = CMSG_DATA(cmsg);
138 end = (int*)(data + cmsg->cmsg_len - CMSG_LEN(0));
139
140 for (int* fd = (int*)data; fd < end; ++fd)
141 *fd = set_cloexec_or_close(*fd);
142 }
143
144 return len;
145}
146
147ssize_t uwac_os_recvmsg_cloexec(int sockfd, struct msghdr* msg, int flags)
148{
149 ssize_t len = 0;
150 len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
151
152 if (len >= 0)
153 return len;
154
155 if (errno != EINVAL)
156 return -1;
157
158 return recvmsg_cloexec_fallback(sockfd, msg, flags);
159}
160
161int uwac_os_epoll_create_cloexec(void)
162{
163 int fd = 0;
164#ifdef EPOLL_CLOEXEC
165 fd = epoll_create1(EPOLL_CLOEXEC);
166
167 if (fd >= 0)
168 return fd;
169
170 if (errno != EINVAL)
171 return -1;
172
173#endif
174 fd = epoll_create(1);
175 return set_cloexec_or_close(fd);
176}
177
178static int secure_mkstemp(char* tmpname)
179{
180 const mode_t mask = umask(S_IRWXU);
181 int fd = mkstemp(tmpname);
182 (void)umask(mask);
183 return fd;
184}
185
186static int create_tmpfile_cloexec(char* tmpname)
187{
188 int fd = 0;
189#ifdef USE_SHM
190 fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
191#elif defined(UWAC_HAVE_MKOSTEMP)
192 fd = mkostemp(tmpname, O_CLOEXEC);
193
194 if (fd >= 0)
195 unlink(tmpname);
196
197#else
198 fd = secure_mkstemp(tmpname);
199
200 if (fd >= 0)
201 {
202 fd = set_cloexec_or_close(fd);
203 unlink(tmpname);
204 }
205
206#endif
207 return fd;
208}
209
210/*
211 * Create a new, unique, anonymous file of the given size, and
212 * return the file descriptor for it. The file descriptor is set
213 * CLOEXEC. The file is immediately suitable for mmap()'ing
214 * the given size at offset zero.
215 *
216 * The file should not have a permanent backing store like a disk,
217 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
218 *
219 * The file name is deleted from the file system.
220 *
221 * The file is suitable for buffer sharing between processes by
222 * transmitting the file descriptor over Unix sockets using the
223 * SCM_RIGHTS methods.
224 *
225 * If the C library implements posix_fallocate(), it is used to
226 * guarantee that disk space is available for the file at the
227 * given size. If disk space is insufficient, errno is set to ENOSPC.
228 * If posix_fallocate() is not supported, program may receive
229 * SIGBUS on accessing mmap()'ed file contents instead.
230 */
231int uwac_create_anonymous_file(off_t size)
232{
233 static const char template[] = "/weston-shared-XXXXXX";
234 size_t length = 0;
235 char* name = nullptr;
236 int fd = 0;
237 int ret = 0;
238 // NOLINTNEXTLINE(concurrency-mt-unsafe)
239 const char* path = getenv("XDG_RUNTIME_DIR");
240
241 if (!path)
242 {
243 errno = ENOENT;
244 return -1;
245 }
246
247#ifdef O_TMPFILE
248 fd = open(path, O_TMPFILE | O_RDWR | O_EXCL, 0600);
249#else
250 /*
251 * Some platforms will not support O_TMPFILE and cannot
252 * reasonably emulate it at first blush. Opt to make them
253 * rely on the create_tmpfile_cloexec() path instead.
254 */
255 fd = -1;
256#endif
257
258 if (fd < 0)
259 {
260 length = strlen(path) + sizeof(template);
261 name = xmalloc(length);
262
263 if (!name)
264 return -1;
265
266 (void)snprintf(name, length, "%s%s", path, template);
267 fd = create_tmpfile_cloexec(name);
268 free(name);
269 }
270
271 if (fd < 0)
272 return -1;
273
274#ifdef UWAC_HAVE_POSIX_FALLOCATE
275 ret = posix_fallocate(fd, 0, size);
276
277 if (ret != 0)
278 {
279 close(fd);
280 errno = ret;
281 return -1;
282 }
283
284#else
285 ret = ftruncate(fd, size);
286
287 if (ret < 0)
288 {
289 close(fd);
290 return -1;
291 }
292
293#endif
294 return fd;
295}