]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/memfd-util.c
basic/memfd: add fcntl() wrappers
[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
4d903003
DR
71int memfd_add_seals(int fd, unsigned int seals) {
72 assert(fd >= 0);
73
74 return RET_NERRNO(fcntl(fd, F_ADD_SEALS, seals));
75}
76
77int memfd_get_seals(int fd, unsigned int *ret_seals) {
78 int r;
79
80 assert(fd >= 0);
81
82 r = RET_NERRNO(fcntl(fd, F_GET_SEALS));
83 if (r < 0)
84 return r;
85
86 if (ret_seals)
87 *ret_seals = r;
88 return 0;
89}
90
fac9c0d5 91int memfd_map(int fd, uint64_t offset, size_t size, void **p) {
ddeb4241
LP
92 void *q;
93 int sealed;
94
4531a9bc
LP
95 assert(fd >= 0);
96 assert(size > 0);
97 assert(p);
ddeb4241 98
fac9c0d5 99 sealed = memfd_get_sealed(fd);
ddeb4241
LP
100 if (sealed < 0)
101 return sealed;
102
23972f42 103 if (sealed)
fac9c0d5 104 q = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset);
23972f42 105 else
fac9c0d5 106 q = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
ddeb4241
LP
107 if (q == MAP_FAILED)
108 return -errno;
109
110 *p = q;
111 return 0;
112}
113
fac9c0d5 114int memfd_set_sealed(int fd) {
4d903003 115 return memfd_add_seals(fd, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
ddeb4241
LP
116}
117
fac9c0d5 118int memfd_get_sealed(int fd) {
4d903003 119 unsigned int seals;
a6082d77 120 int r;
ddeb4241 121
4d903003 122 r = memfd_get_seals(fd, &seals);
ddeb4241 123 if (r < 0)
4d903003 124 return r;
ddeb4241 125
17915ea5 126 /* We ignore F_SEAL_EXEC here to support older kernels. */
4d903003 127 return FLAGS_SET(seals, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
ddeb4241
LP
128}
129
fac9c0d5 130int memfd_get_size(int fd, uint64_t *sz) {
a6082d77 131 struct stat stat;
ddeb4241 132
4531a9bc
LP
133 assert(fd >= 0);
134 assert(sz);
ddeb4241 135
7c248223 136 if (fstat(fd, &stat) < 0)
ddeb4241
LP
137 return -errno;
138
a6082d77 139 *sz = stat.st_size;
5755381f 140 return 0;
ddeb4241
LP
141}
142
fac9c0d5 143int memfd_set_size(int fd, uint64_t sz) {
4531a9bc 144 assert(fd >= 0);
ddeb4241 145
7c248223 146 return RET_NERRNO(ftruncate(fd, sz));
ddeb4241 147}
453a0c29 148
4531a9bc 149int memfd_new_and_map(const char *name, size_t sz, void **p) {
254d1313 150 _cleanup_close_ int fd = -EBADF;
453a0c29
LP
151 int r;
152
4531a9bc
LP
153 assert(sz > 0);
154 assert(p);
155
156 fd = memfd_new(name);
157 if (fd < 0)
158 return fd;
453a0c29 159
4531a9bc 160 r = memfd_set_size(fd, sz);
8a02deca 161 if (r < 0)
453a0c29 162 return r;
453a0c29 163
4531a9bc 164 r = memfd_map(fd, 0, sz, p);
8a02deca 165 if (r < 0)
453a0c29 166 return r;
453a0c29 167
c10d6bdb 168 return TAKE_FD(fd);
453a0c29 169}
44777d7a
DDM
170
171int memfd_new_and_seal(const char *name, const void *data, size_t sz) {
172 _cleanup_close_ int fd = -EBADF;
173 ssize_t n;
174 off_t f;
175 int r;
176
177 assert(data || sz == 0);
178
179 fd = memfd_new(name);
180 if (fd < 0)
181 return fd;
182
183 if (sz > 0) {
184 n = write(fd, data, sz);
185 if (n < 0)
186 return -errno;
187 if ((size_t) n != sz)
188 return -EIO;
189
190 f = lseek(fd, 0, SEEK_SET);
191 if (f != 0)
192 return -errno;
193 }
194
195 r = memfd_set_sealed(fd);
196 if (r < 0)
197 return r;
198
199 return TAKE_FD(fd);
200}