1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#include "qemu/osdep.h"
29
30#include <glib.h>
31#include <glib/gprintf.h>
32
33#include <sys/mman.h>
34
35#include "qemu/memfd.h"
36
37#ifdef CONFIG_MEMFD
38#include <sys/memfd.h>
39#elif defined CONFIG_LINUX
40#include <sys/syscall.h>
41#include <asm/unistd.h>
42
43static int memfd_create(const char *name, unsigned int flags)
44{
45#ifdef __NR_memfd_create
46 return syscall(__NR_memfd_create, name, flags);
47#else
48 return -1;
49#endif
50}
51#endif
52
53#ifndef MFD_CLOEXEC
54#define MFD_CLOEXEC 0x0001U
55#endif
56
57#ifndef MFD_ALLOW_SEALING
58#define MFD_ALLOW_SEALING 0x0002U
59#endif
60
61
62
63
64
65
66
67void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals,
68 int *fd)
69{
70 void *ptr;
71 int mfd = -1;
72
73 *fd = -1;
74
75#ifdef CONFIG_LINUX
76 if (seals) {
77 mfd = memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
78 }
79
80 if (mfd == -1) {
81
82 mfd = memfd_create(name, MFD_CLOEXEC);
83 seals = 0;
84 }
85#endif
86
87 if (mfd != -1) {
88 if (ftruncate(mfd, size) == -1) {
89 perror("ftruncate");
90 close(mfd);
91 return NULL;
92 }
93
94 if (seals && fcntl(mfd, F_ADD_SEALS, seals) == -1) {
95 perror("fcntl");
96 close(mfd);
97 return NULL;
98 }
99 } else {
100 const char *tmpdir = g_get_tmp_dir();
101 gchar *fname;
102
103 fname = g_strdup_printf("%s/memfd-XXXXXX", tmpdir);
104 mfd = mkstemp(fname);
105 unlink(fname);
106 g_free(fname);
107
108 if (mfd == -1) {
109 perror("mkstemp");
110 return NULL;
111 }
112
113 if (ftruncate(mfd, size) == -1) {
114 perror("ftruncate");
115 close(mfd);
116 return NULL;
117 }
118 }
119
120 ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, 0);
121 if (ptr == MAP_FAILED) {
122 perror("mmap");
123 close(mfd);
124 return NULL;
125 }
126
127 *fd = mfd;
128 return ptr;
129}
130
131void qemu_memfd_free(void *ptr, size_t size, int fd)
132{
133 if (ptr) {
134 munmap(ptr, size);
135 }
136
137 if (fd != -1) {
138 close(fd);
139 }
140}
141
142enum {
143 MEMFD_KO,
144 MEMFD_OK,
145 MEMFD_TODO
146};
147
148bool qemu_memfd_check(void)
149{
150 static int memfd_check = MEMFD_TODO;
151
152 if (memfd_check == MEMFD_TODO) {
153 int fd;
154 void *ptr;
155
156 ptr = qemu_memfd_alloc("test", 4096, 0, &fd);
157 memfd_check = ptr ? MEMFD_OK : MEMFD_KO;
158 qemu_memfd_free(ptr, 4096, fd);
159 }
160
161 return memfd_check == MEMFD_OK;
162}
163