xref: /qemu/util/memfd.c (revision d3592199)
1f04cf923SMarc-André Lureau /*
2f04cf923SMarc-André Lureau  * memfd.c
3f04cf923SMarc-André Lureau  *
4f04cf923SMarc-André Lureau  * Copyright (c) 2015 Red Hat, Inc.
5f04cf923SMarc-André Lureau  *
6f04cf923SMarc-André Lureau  * QEMU library functions on POSIX which are shared between QEMU and
7f04cf923SMarc-André Lureau  * the QEMU tools.
8f04cf923SMarc-André Lureau  *
9f04cf923SMarc-André Lureau  * Permission is hereby granted, free of charge, to any person obtaining a copy
10f04cf923SMarc-André Lureau  * of this software and associated documentation files (the "Software"), to deal
11f04cf923SMarc-André Lureau  * in the Software without restriction, including without limitation the rights
12f04cf923SMarc-André Lureau  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13f04cf923SMarc-André Lureau  * copies of the Software, and to permit persons to whom the Software is
14f04cf923SMarc-André Lureau  * furnished to do so, subject to the following conditions:
15f04cf923SMarc-André Lureau  *
16f04cf923SMarc-André Lureau  * The above copyright notice and this permission notice shall be included in
17f04cf923SMarc-André Lureau  * all copies or substantial portions of the Software.
18f04cf923SMarc-André Lureau  *
19f04cf923SMarc-André Lureau  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20f04cf923SMarc-André Lureau  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21f04cf923SMarc-André Lureau  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22f04cf923SMarc-André Lureau  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23f04cf923SMarc-André Lureau  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24f04cf923SMarc-André Lureau  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25f04cf923SMarc-André Lureau  * THE SOFTWARE.
26f04cf923SMarc-André Lureau  */
27f04cf923SMarc-André Lureau 
28f04cf923SMarc-André Lureau #include "qemu/osdep.h"
29f04cf923SMarc-André Lureau 
30*d3592199SMarc-André Lureau #include <glib.h>
31*d3592199SMarc-André Lureau #include <glib/gprintf.h>
32*d3592199SMarc-André Lureau 
33*d3592199SMarc-André Lureau #include <sys/mman.h>
34*d3592199SMarc-André Lureau 
35f04cf923SMarc-André Lureau #include "qemu/memfd.h"
36f04cf923SMarc-André Lureau 
37f04cf923SMarc-André Lureau #ifdef CONFIG_MEMFD
38f04cf923SMarc-André Lureau #include <sys/memfd.h>
39f04cf923SMarc-André Lureau #elif defined CONFIG_LINUX
40f04cf923SMarc-André Lureau #include <sys/syscall.h>
41f04cf923SMarc-André Lureau #include <asm/unistd.h>
42f04cf923SMarc-André Lureau 
43*d3592199SMarc-André Lureau static int memfd_create(const char *name, unsigned int flags)
44f04cf923SMarc-André Lureau {
45f04cf923SMarc-André Lureau #ifdef __NR_memfd_create
46f04cf923SMarc-André Lureau     return syscall(__NR_memfd_create, name, flags);
47f04cf923SMarc-André Lureau #else
48f04cf923SMarc-André Lureau     return -1;
49f04cf923SMarc-André Lureau #endif
50f04cf923SMarc-André Lureau }
51f04cf923SMarc-André Lureau #endif
52f04cf923SMarc-André Lureau 
53f04cf923SMarc-André Lureau #ifndef MFD_CLOEXEC
54f04cf923SMarc-André Lureau #define MFD_CLOEXEC 0x0001U
55f04cf923SMarc-André Lureau #endif
56f04cf923SMarc-André Lureau 
57f04cf923SMarc-André Lureau #ifndef MFD_ALLOW_SEALING
58f04cf923SMarc-André Lureau #define MFD_ALLOW_SEALING 0x0002U
59f04cf923SMarc-André Lureau #endif
60*d3592199SMarc-André Lureau 
61*d3592199SMarc-André Lureau /*
62*d3592199SMarc-André Lureau  * This is a best-effort helper for shared memory allocation, with
63*d3592199SMarc-André Lureau  * optional sealing. The helper will do his best to allocate using
64*d3592199SMarc-André Lureau  * memfd with sealing, but may fallback on other methods without
65*d3592199SMarc-André Lureau  * sealing.
66*d3592199SMarc-André Lureau  */
67*d3592199SMarc-André Lureau void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals,
68*d3592199SMarc-André Lureau                        int *fd)
69*d3592199SMarc-André Lureau {
70*d3592199SMarc-André Lureau     void *ptr;
71*d3592199SMarc-André Lureau     int mfd = -1;
72*d3592199SMarc-André Lureau 
73*d3592199SMarc-André Lureau     *fd = -1;
74*d3592199SMarc-André Lureau 
75*d3592199SMarc-André Lureau #ifdef CONFIG_LINUX
76*d3592199SMarc-André Lureau     if (seals) {
77*d3592199SMarc-André Lureau         mfd = memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
78*d3592199SMarc-André Lureau     }
79*d3592199SMarc-André Lureau 
80*d3592199SMarc-André Lureau     if (mfd == -1) {
81*d3592199SMarc-André Lureau         /* some systems have memfd without sealing */
82*d3592199SMarc-André Lureau         mfd = memfd_create(name, MFD_CLOEXEC);
83*d3592199SMarc-André Lureau         seals = 0;
84*d3592199SMarc-André Lureau     }
85*d3592199SMarc-André Lureau #endif
86*d3592199SMarc-André Lureau 
87*d3592199SMarc-André Lureau     if (mfd != -1) {
88*d3592199SMarc-André Lureau         if (ftruncate(mfd, size) == -1) {
89*d3592199SMarc-André Lureau             perror("ftruncate");
90*d3592199SMarc-André Lureau             close(mfd);
91*d3592199SMarc-André Lureau             return NULL;
92*d3592199SMarc-André Lureau         }
93*d3592199SMarc-André Lureau 
94*d3592199SMarc-André Lureau         if (seals && fcntl(mfd, F_ADD_SEALS, seals) == -1) {
95*d3592199SMarc-André Lureau             perror("fcntl");
96*d3592199SMarc-André Lureau             close(mfd);
97*d3592199SMarc-André Lureau             return NULL;
98*d3592199SMarc-André Lureau         }
99*d3592199SMarc-André Lureau     } else {
100*d3592199SMarc-André Lureau         perror("memfd");
101*d3592199SMarc-André Lureau         return NULL;
102*d3592199SMarc-André Lureau     }
103*d3592199SMarc-André Lureau 
104*d3592199SMarc-André Lureau     ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, 0);
105*d3592199SMarc-André Lureau     if (ptr == MAP_FAILED) {
106*d3592199SMarc-André Lureau         perror("mmap");
107*d3592199SMarc-André Lureau         close(mfd);
108*d3592199SMarc-André Lureau         return NULL;
109*d3592199SMarc-André Lureau     }
110*d3592199SMarc-André Lureau 
111*d3592199SMarc-André Lureau     *fd = mfd;
112*d3592199SMarc-André Lureau     return ptr;
113*d3592199SMarc-André Lureau }
114*d3592199SMarc-André Lureau 
115*d3592199SMarc-André Lureau void qemu_memfd_free(void *ptr, size_t size, int fd)
116*d3592199SMarc-André Lureau {
117*d3592199SMarc-André Lureau     if (ptr) {
118*d3592199SMarc-André Lureau         munmap(ptr, size);
119*d3592199SMarc-André Lureau     }
120*d3592199SMarc-André Lureau 
121*d3592199SMarc-André Lureau     if (fd != -1) {
122*d3592199SMarc-André Lureau         close(fd);
123*d3592199SMarc-André Lureau     }
124*d3592199SMarc-André Lureau }
125