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#if defined(__FreeBSD__) || defined(__DragonFly__)
42#define USE_SHM
43#endif
44
45/* uClibc and uClibc-ng don't provide O_TMPFILE */
46#if !defined(O_TMPFILE) && !defined(__FreeBSD__)
47#define O_TMPFILE (020000000 | O_DIRECTORY)
48#endif
49
50#include <sys/types.h>
51#include <sys/socket.h>
52#ifdef USE_SHM
53#include <sys/mman.h>
54#endif
55#include <unistd.h>
56#include <fcntl.h>
57#include <errno.h>
58#include <stdlib.h>
59#include <stdio.h>
60#include <string.h>
61#include <sys/epoll.h>
62#include <sys/stat.h>
63
64#include <winpr/wtypes.h>
65#include <uwac/config.h>
66
67#include "uwac-os.h"
68#include "uwac-utils.h"
69
70static int set_cloexec_or_close(int fd)
71{
72 long flags = 0;
73
74 if (fd == -1)
75 return -1;
76
77 flags = fcntl(fd, F_GETFD);
78
79 if (flags == -1)
80 goto err;
81
82 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
83 goto err;
84
85 return fd;
86err:
87 close(fd);
88 return -1;
89}
90
91int uwac_os_socket_cloexec(int domain, int type, int protocol)
92{
93 int fd = 0;
94 fd = socket(domain, type | SOCK_CLOEXEC, protocol);
95
96 if (fd >= 0)
97 return fd;
98
99 if (errno != EINVAL)
100 return -1;
101
102 fd = socket(domain, type, protocol);
103 return set_cloexec_or_close(fd);
104}
105
106int uwac_os_dupfd_cloexec(int fd, long minfd)
107{
108 int newfd = 0;
109 newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
110
111 if (newfd >= 0)
112 return newfd;
113
114 if (errno != EINVAL)
115 return -1;
116
117 newfd = fcntl(fd, F_DUPFD, minfd);
118 return set_cloexec_or_close(newfd);
119}
120
121static ssize_t recvmsg_cloexec_fallback(int sockfd, struct msghdr* msg, int flags)
122{
123 ssize_t len = 0;
124 struct cmsghdr* cmsg = nullptr;
125 unsigned char* data = nullptr;
126 int* end = nullptr;
127 len = recvmsg(sockfd, msg, flags);
128
129 if (len == -1)
130 return -1;
131
132 if (!msg->msg_control || msg->msg_controllen == 0)
133 return len;
134
135 cmsg = CMSG_FIRSTHDR(msg);
136
137 for (; cmsg != nullptr; cmsg = CMSG_NXTHDR(msg, cmsg))
138 {
139 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
140 continue;
141
142 data = CMSG_DATA(cmsg);
143 end = (int*)(data + cmsg->cmsg_len - CMSG_LEN(0));
144
145 for (int* fd = (int*)data; fd < end; ++fd)
146 *fd = set_cloexec_or_close(*fd);
147 }
148
149 return len;
150}
151
152ssize_t uwac_os_recvmsg_cloexec(int sockfd, struct msghdr* msg, int flags)
153{
154 ssize_t len = 0;
155 len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
156
157 if (len >= 0)
158 return len;
159
160 if (errno != EINVAL)
161 return -1;
162
163 return recvmsg_cloexec_fallback(sockfd, msg, flags);
164}
165
166int uwac_os_epoll_create_cloexec(void)
167{
168 int fd = 0;
169#ifdef EPOLL_CLOEXEC
170 fd = epoll_create1(EPOLL_CLOEXEC);
171
172 if (fd >= 0)
173 return fd;
174
175 if (errno != EINVAL)
176 return -1;
177
178#endif
179 fd = epoll_create(1);
180 return set_cloexec_or_close(fd);
181}
182
183static int secure_mkstemp(char* tmpname)
184{
185 const mode_t mask = umask(S_IRWXU);
186 int fd = mkstemp(tmpname);
187 (void)umask(mask);
188 return fd;
189}
190
191static int create_tmpfile_cloexec(char* tmpname)
192{
193 int fd = 0;
194#ifdef USE_SHM
195 fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
196#elif defined(UWAC_HAVE_MKOSTEMP)
197 fd = mkostemp(tmpname, O_CLOEXEC);
198
199 if (fd >= 0)
200 unlink(tmpname);
201
202#else
203 fd = secure_mkstemp(tmpname);
204
205 if (fd >= 0)
206 {
207 fd = set_cloexec_or_close(fd);
208 unlink(tmpname);
209 }
210
211#endif
212 return fd;
213}
214
215/*
216 * Create a new, unique, anonymous file of the given size, and
217 * return the file descriptor for it. The file descriptor is set
218 * CLOEXEC. The file is immediately suitable for mmap()'ing
219 * the given size at offset zero.
220 *
221 * The file should not have a permanent backing store like a disk,
222 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
223 *
224 * The file name is deleted from the file system.
225 *
226 * The file is suitable for buffer sharing between processes by
227 * transmitting the file descriptor over Unix sockets using the
228 * SCM_RIGHTS methods.
229 *
230 * If the C library implements posix_fallocate(), it is used to
231 * guarantee that disk space is available for the file at the
232 * given size. If disk space is insufficient, errno is set to ENOSPC.
233 * If posix_fallocate() is not supported, program may receive
234 * SIGBUS on accessing mmap()'ed file contents instead.
235 */
236int uwac_create_anonymous_file(off_t size)
237{
238 static const char template[] = "/weston-shared-XXXXXX";
239 size_t length = 0;
240 char* name = nullptr;
241 int fd = 0;
242 int ret = 0;
243 // NOLINTNEXTLINE(concurrency-mt-unsafe)
244 const char* path = getenv("XDG_RUNTIME_DIR");
245
246 if (!path)
247 {
248 errno = ENOENT;
249 return -1;
250 }
251
252#ifdef O_TMPFILE
253 fd = open(path, O_TMPFILE | O_RDWR | O_EXCL, 0600);
254#else
255 /*
256 * Some platforms (e.g. FreeBSD) won't support O_TMPFILE and can't
257 * reasonably emulate it at first blush. Opt to make them rely on
258 * the create_tmpfile_cloexec() path instead.
259 */
260 fd = -1;
261#endif
262
263 if (fd < 0)
264 {
265 length = strlen(path) + sizeof(template);
266 name = xmalloc(length);
267
268 if (!name)
269 return -1;
270
271 (void)snprintf(name, length, "%s%s", path, template);
272 fd = create_tmpfile_cloexec(name);
273 free(name);
274 }
275
276 if (fd < 0)
277 return -1;
278
279#ifdef UWAC_HAVE_POSIX_FALLOCATE
280 ret = posix_fallocate(fd, 0, size);
281
282 if (ret != 0)
283 {
284 close(fd);
285 errno = ret;
286 return -1;
287 }
288
289#else
290 ret = ftruncate(fd, size);
291
292 if (ret < 0)
293 {
294 close(fd);
295 return -1;
296 }
297
298#endif
299 return fd;
300}