1 /*
2 * Copyright © 2012 Collabora, Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include "config.h"
27
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <sys/epoll.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <libweston/zalloc.h>
37 #include <sys/mman.h>
38
39 #include "os-compatibility.h"
40
41 #define READONLY_SEALS (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)
42
43 int
os_fd_set_cloexec(int fd)44 os_fd_set_cloexec(int fd)
45 {
46 long flags;
47
48 if (fd == -1)
49 return -1;
50
51 flags = fcntl(fd, F_GETFD);
52 if (flags == -1)
53 return -1;
54
55 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
56 return -1;
57
58 return 0;
59 }
60
61 static int
set_cloexec_or_close(int fd)62 set_cloexec_or_close(int fd)
63 {
64 if (os_fd_set_cloexec(fd) != 0) {
65 close(fd);
66 return -1;
67 }
68 return fd;
69 }
70
71 int
os_socketpair_cloexec(int domain,int type,int protocol,int * sv)72 os_socketpair_cloexec(int domain, int type, int protocol, int *sv)
73 {
74 int ret;
75
76 #ifdef SOCK_CLOEXEC
77 ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
78 if (ret == 0 || errno != EINVAL)
79 return ret;
80 #endif
81
82 ret = socketpair(domain, type, protocol, sv);
83 if (ret < 0)
84 return ret;
85
86 sv[0] = set_cloexec_or_close(sv[0]);
87 sv[1] = set_cloexec_or_close(sv[1]);
88
89 if (sv[0] != -1 && sv[1] != -1)
90 return 0;
91
92 close(sv[0]);
93 close(sv[1]);
94 return -1;
95 }
96
97 int
os_epoll_create_cloexec(void)98 os_epoll_create_cloexec(void)
99 {
100 int fd;
101
102 #ifdef EPOLL_CLOEXEC
103 fd = epoll_create1(EPOLL_CLOEXEC);
104 if (fd >= 0)
105 return fd;
106 if (errno != EINVAL)
107 return -1;
108 #endif
109
110 fd = epoll_create(1);
111 return set_cloexec_or_close(fd);
112 }
113
114 static int
create_tmpfile_cloexec(char * tmpname)115 create_tmpfile_cloexec(char *tmpname)
116 {
117 int fd;
118
119 #ifdef HAVE_MKOSTEMP
120 fd = mkostemp(tmpname, O_CLOEXEC);
121 if (fd >= 0)
122 unlink(tmpname);
123 #else
124 fd = mkstemp(tmpname);
125 if (fd >= 0) {
126 fd = set_cloexec_or_close(fd);
127 unlink(tmpname);
128 }
129 #endif
130
131 return fd;
132 }
133
134 /*
135 * Create a new, unique, anonymous file of the given size, and
136 * return the file descriptor for it. The file descriptor is set
137 * CLOEXEC. The file is immediately suitable for mmap()'ing
138 * the given size at offset zero.
139 *
140 * The file should not have a permanent backing store like a disk,
141 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
142 *
143 * The file name is deleted from the file system.
144 *
145 * The file is suitable for buffer sharing between processes by
146 * transmitting the file descriptor over Unix sockets using the
147 * SCM_RIGHTS methods.
148 *
149 * If the C library implements posix_fallocate(), it is used to
150 * guarantee that disk space is available for the file at the
151 * given size. If disk space is insufficient, errno is set to ENOSPC.
152 * If posix_fallocate() is not supported, program may receive
153 * SIGBUS on accessing mmap()'ed file contents instead.
154 *
155 * If the C library implements memfd_create(), it is used to create the
156 * file purely in memory, without any backing file name on the file
157 * system, and then sealing off the possibility of shrinking it. This
158 * can then be checked before accessing mmap()'ed file contents, to
159 * make sure SIGBUS can't happen. It also avoids requiring
160 * XDG_RUNTIME_DIR.
161 */
162 int
os_create_anonymous_file(off_t size)163 os_create_anonymous_file(off_t size)
164 {
165 static const char template[] = "/weston-shared-XXXXXX";
166 const char *path;
167 char *name;
168 int fd;
169 int ret;
170
171 #ifdef HAVE_MEMFD_CREATE
172 fd = memfd_create("weston-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
173 if (fd >= 0) {
174 /* We can add this seal before calling posix_fallocate(), as
175 * the file is currently zero-sized anyway.
176 *
177 * There is also no need to check for the return value, we
178 * couldn't do anything with it anyway.
179 */
180 fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
181 } else
182 #endif
183 {
184 path = getenv("XDG_RUNTIME_DIR");
185 if (!path) {
186 errno = ENOENT;
187 return -1;
188 }
189
190 name = malloc(strlen(path) + sizeof(template));
191 if (!name)
192 return -1;
193
194 strcpy(name, path);
195 strcat(name, template);
196
197 fd = create_tmpfile_cloexec(name);
198
199 free(name);
200
201 if (fd < 0)
202 return -1;
203 }
204
205 #ifdef HAVE_POSIX_FALLOCATE
206 do {
207 ret = posix_fallocate(fd, 0, size);
208 } while (ret == EINTR);
209 if (ret != 0) {
210 close(fd);
211 errno = ret;
212 return -1;
213 }
214 #else
215 do {
216 ret = ftruncate(fd, size);
217 } while (ret < 0 && errno == EINTR);
218 if (ret < 0) {
219 close(fd);
220 return -1;
221 }
222 #endif
223
224 return fd;
225 }
226
227 #ifndef HAVE_STRCHRNUL
228 char *
strchrnul(const char * s,int c)229 strchrnul(const char *s, int c)
230 {
231 while (*s && *s != c)
232 s++;
233 return (char *)s;
234 }
235 #endif
236
237 struct ro_anonymous_file {
238 int fd;
239 size_t size;
240 };
241
242 /** Create a new anonymous read-only file of the given size and the given data
243 *
244 * \param size The size of \p data.
245 * \param data The data of the file with the size \p size.
246 * \return A new \c ro_anonymous_file, or NULL on failure.
247 *
248 * The intended use-case is for sending mid-sized data from the compositor
249 * to clients.
250 * If the function fails errno is set.
251 */
252 struct ro_anonymous_file *
os_ro_anonymous_file_create(size_t size,const char * data)253 os_ro_anonymous_file_create(size_t size,
254 const char *data)
255 {
256 struct ro_anonymous_file *file;
257 void *map;
258
259 file = zalloc(sizeof *file);
260 if (!file) {
261 errno = ENOMEM;
262 return NULL;
263 }
264
265 file->size = size;
266 file->fd = os_create_anonymous_file(size);
267 if (file->fd == -1)
268 goto err_free;
269
270 map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, file->fd, 0);
271 if (map == MAP_FAILED)
272 goto err_close;
273
274 memcpy(map, data, size);
275
276 munmap(map, size);
277
278 #ifdef HAVE_MEMFD_CREATE
279 /* try to put seals on the file to make it read-only so that we can
280 * return the fd later directly when support_shared is not set.
281 * os_ro_anonymous_file_get_fd can handle the fd even if it is not
282 * sealed read-only and will instead create a new anonymous file on
283 * each invocation.
284 */
285 fcntl(file->fd, F_ADD_SEALS, READONLY_SEALS);
286 #endif
287
288 return file;
289
290 err_close:
291 close(file->fd);
292 err_free:
293 free(file);
294 return NULL;
295 }
296
297 /** Destroy an anonymous read-only file
298 *
299 * \param file The file to destroy.
300 */
301 void
os_ro_anonymous_file_destroy(struct ro_anonymous_file * file)302 os_ro_anonymous_file_destroy(struct ro_anonymous_file *file)
303 {
304 close(file->fd);
305 free(file);
306 }
307
308 /** Get the size of an anonymous read-only file
309 *
310 * \param file The file to get the size of.
311 * \return The size of the file.
312 */
313 size_t
os_ro_anonymous_file_size(struct ro_anonymous_file * file)314 os_ro_anonymous_file_size(struct ro_anonymous_file *file)
315 {
316 return file->size;
317 }
318
319 /** Returns a file descriptor for the given file, ready to be send to a client.
320 *
321 * \param file The file for which to get a file descriptor.
322 * \param mapmode Describes the ways in which the returned file descriptor can
323 * be used with mmap.
324 * \return A file descriptor for the given file that can be send to a client
325 * or -1 on failure.
326 *
327 * The returned file descriptor must not be shared between multiple clients.
328 * When \p mapmode is RO_ANONYMOUS_FILE_MAPMODE_PRIVATE the file descriptor is
329 * only guaranteed to be mmapable with \c MAP_PRIVATE, when \p mapmode is
330 * RO_ANONYMOUS_FILE_MAPMODE_SHARED the file descriptor can be mmaped with
331 * either MAP_PRIVATE or MAP_SHARED.
332 * When you're done with the fd you must call \c os_ro_anonymous_file_put_fd
333 * instead of calling \c close.
334 * If the function fails errno is set.
335 */
336 int
os_ro_anonymous_file_get_fd(struct ro_anonymous_file * file,enum ro_anonymous_file_mapmode mapmode)337 os_ro_anonymous_file_get_fd(struct ro_anonymous_file *file,
338 enum ro_anonymous_file_mapmode mapmode)
339 {
340 void *src, *dst;
341 int fd;
342
343 #ifdef HAVE_MEMFD_CREATE
344 int seals = fcntl(file->fd, F_GET_SEALS);
345
346 /* file was sealed for read-only and we don't have to support MAP_SHARED
347 * so we can simply pass the memfd fd
348 */
349 if (seals != -1 && mapmode == RO_ANONYMOUS_FILE_MAPMODE_PRIVATE &&
350 (seals & READONLY_SEALS) == READONLY_SEALS)
351 return file->fd;
352 #endif
353
354 /* for all other cases we create a new anonymous file that can be mapped
355 * with MAP_SHARED and copy the contents to it and return that instead
356 */
357 fd = os_create_anonymous_file(file->size);
358 if (fd == -1)
359 return fd;
360
361 src = mmap(NULL, file->size, PROT_READ, MAP_PRIVATE, file->fd, 0);
362 if (src == MAP_FAILED) {
363 close(fd);
364 return -1;
365 }
366
367 dst = mmap(NULL, file->size, PROT_WRITE, MAP_SHARED, fd, 0);
368 if (dst == MAP_FAILED) {
369 close(fd);
370 munmap(src, file->size);
371 return -1;
372 }
373
374 memcpy(dst, src, file->size);
375 munmap(src, file->size);
376 munmap(dst, file->size);
377
378 return fd;
379 }
380
381 /** Release a file descriptor returned by \c os_ro_anonymous_file_get_fd
382 *
383 * \param fd A file descriptor returned by \c os_ro_anonymous_file_get_fd.
384 * \return 0 on success, or -1 on failure.
385 *
386 * This function must be called for every file descriptor created with
387 * \c os_ro_anonymous_file_get_fd to not leake any resources.
388 * If the function fails errno is set.
389 */
390 int
os_ro_anonymous_file_put_fd(int fd)391 os_ro_anonymous_file_put_fd(int fd)
392 {
393 #ifdef HAVE_MEMFD_CREATE
394 int seals = fcntl(fd, F_GET_SEALS);
395 if (seals == -1 && errno != EINVAL)
396 return -1;
397
398 /* The only case in which we do NOT have to close the file is when the file
399 * was sealed for read-only
400 */
401 if (seals != -1 && (seals & READONLY_SEALS) == READONLY_SEALS)
402 return 0;
403 #endif
404
405 close(fd);
406 return 0;
407 }
408