]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/memfd-util.c
memfd-util: memfd may also have F_SEAL_EXEC flag
[thirdparty/systemd.git] / src / basic / memfd-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
ddeb4241 2
11c3a366 3#include <errno.h>
11c3a366
TA
4#include <sys/stat.h>
5#include <unistd.h>
349cc4a5 6#if HAVE_LINUX_MEMFD_H
07630cea 7#include <linux/memfd.h>
27c64db6 8#endif
07630cea 9#include <stdio.h>
07630cea 10#include <sys/prctl.h>
27c64db6 11
b5efdb8a 12#include "alloc-util.h"
7c248223 13#include "errno-util.h"
3ffd4af2 14#include "fd-util.h"
93cc7779 15#include "macro.h"
3ffd4af2 16#include "memfd-util.h"
f5947a5e
YW
17#include "missing_fcntl.h"
18#include "missing_mman.h"
19#include "missing_syscall.h"
07630cea
LP
20#include "string-util.h"
21#include "utf8.h"
ddeb4241 22
ad62530e
TW
23int memfd_create_wrapper(const char *name, unsigned mode) {
24 unsigned mode_compat;
25 int mfd;
26
27 mfd = RET_NERRNO(memfd_create(name, mode));
28 if (mfd != -EINVAL)
29 return mfd;
30
31 mode_compat = mode & ~(MFD_EXEC | MFD_NOEXEC_SEAL);
32
33 if (mode == mode_compat)
34 return mfd;
35
36 return RET_NERRNO(memfd_create(name, mode_compat));
37}
38
4531a9bc 39int memfd_new(const char *name) {
7f96b1d8 40 _cleanup_free_ char *g = NULL;
ddeb4241 41
5755381f 42 if (!name) {
7f96b1d8
LP
43 char pr[17] = {};
44
45 /* If no name is specified we generate one. We include
46 * a hint indicating our library implementation, and
47 * add the thread name to it */
48
49 assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0);
50
51 if (isempty(pr))
52 name = "sd";
53 else {
5755381f
LP
54 _cleanup_free_ char *e = NULL;
55
56 e = utf8_escape_invalid(pr);
57 if (!e)
58 return -ENOMEM;
59
b910cc72 60 g = strjoin("sd-", e);
7f96b1d8
LP
61 if (!g)
62 return -ENOMEM;
63
64 name = g;
65 }
66 }
67
c29715a8 68 return memfd_create_wrapper(name, MFD_ALLOW_SEALING | MFD_CLOEXEC | MFD_NOEXEC_SEAL);
ddeb4241
LP
69}
70
fac9c0d5 71int memfd_map(int fd, uint64_t offset, size_t size, void **p) {
ddeb4241
LP
72 void *q;
73 int sealed;
74
4531a9bc
LP
75 assert(fd >= 0);
76 assert(size > 0);
77 assert(p);
ddeb4241 78
fac9c0d5 79 sealed = memfd_get_sealed(fd);
ddeb4241
LP
80 if (sealed < 0)
81 return sealed;
82
23972f42 83 if (sealed)
fac9c0d5 84 q = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset);
23972f42 85 else
fac9c0d5 86 q = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
ddeb4241
LP
87 if (q == MAP_FAILED)
88 return -errno;
89
90 *p = q;
91 return 0;
92}
93
fac9c0d5 94int memfd_set_sealed(int fd) {
4531a9bc 95 assert(fd >= 0);
ddeb4241 96
7c248223 97 return RET_NERRNO(fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL));
ddeb4241
LP
98}
99
fac9c0d5 100int memfd_get_sealed(int fd) {
a6082d77 101 int r;
ddeb4241 102
4531a9bc 103 assert(fd >= 0);
ddeb4241 104
fac9c0d5 105 r = fcntl(fd, F_GET_SEALS);
ddeb4241
LP
106 if (r < 0)
107 return -errno;
108
17915ea5
YW
109 /* We ignore F_SEAL_EXEC here to support older kernels. */
110 return FLAGS_SET(r, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
ddeb4241
LP
111}
112
fac9c0d5 113int memfd_get_size(int fd, uint64_t *sz) {
a6082d77 114 struct stat stat;
ddeb4241 115
4531a9bc
LP
116 assert(fd >= 0);
117 assert(sz);
ddeb4241 118
7c248223 119 if (fstat(fd, &stat) < 0)
ddeb4241
LP
120 return -errno;
121
a6082d77 122 *sz = stat.st_size;
5755381f 123 return 0;
ddeb4241
LP
124}
125
fac9c0d5 126int memfd_set_size(int fd, uint64_t sz) {
4531a9bc 127 assert(fd >= 0);
ddeb4241 128
7c248223 129 return RET_NERRNO(ftruncate(fd, sz));
ddeb4241 130}
453a0c29 131
4531a9bc 132int memfd_new_and_map(const char *name, size_t sz, void **p) {
254d1313 133 _cleanup_close_ int fd = -EBADF;
453a0c29
LP
134 int r;
135
4531a9bc
LP
136 assert(sz > 0);
137 assert(p);
138
139 fd = memfd_new(name);
140 if (fd < 0)
141 return fd;
453a0c29 142
4531a9bc 143 r = memfd_set_size(fd, sz);
8a02deca 144 if (r < 0)
453a0c29 145 return r;
453a0c29 146
4531a9bc 147 r = memfd_map(fd, 0, sz, p);
8a02deca 148 if (r < 0)
453a0c29 149 return r;
453a0c29 150
c10d6bdb 151 return TAKE_FD(fd);
453a0c29 152}
44777d7a
DDM
153
154int memfd_new_and_seal(const char *name, const void *data, size_t sz) {
155 _cleanup_close_ int fd = -EBADF;
156 ssize_t n;
157 off_t f;
158 int r;
159
160 assert(data || sz == 0);
161
162 fd = memfd_new(name);
163 if (fd < 0)
164 return fd;
165
166 if (sz > 0) {
167 n = write(fd, data, sz);
168 if (n < 0)
169 return -errno;
170 if ((size_t) n != sz)
171 return -EIO;
172
173 f = lseek(fd, 0, SEEK_SET);
174 if (f != 0)
175 return -errno;
176 }
177
178 r = memfd_set_sealed(fd);
179 if (r < 0)
180 return r;
181
182 return TAKE_FD(fd);
183}