]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/memfd-util.c
basic/include: replace _Static_assert() with static_assert()
[thirdparty/systemd.git] / src / basic / memfd-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
ddeb4241 2
237bdd27 3#include <sched.h>
07630cea 4#include <stdio.h>
07630cea 5#include <sys/prctl.h>
c415a481
MY
6#include <sys/stat.h>
7#include <unistd.h>
27c64db6 8
b5efdb8a 9#include "alloc-util.h"
7c248223 10#include "errno-util.h"
3ffd4af2
LP
11#include "fd-util.h"
12#include "memfd-util.h"
07630cea
LP
13#include "string-util.h"
14#include "utf8.h"
ddeb4241 15
ad62530e
TW
16int memfd_create_wrapper(const char *name, unsigned mode) {
17 unsigned mode_compat;
18 int mfd;
19
9b1d97cc
LP
20 assert(name);
21
22 /* Wrapper around memfd_create() which adds compat with older kernels where memfd_create() didn't
23 * support MFD_EXEC/MFD_NOEXEC_SEAL. (kernel 6.3+) */
24
ad62530e
TW
25 mfd = RET_NERRNO(memfd_create(name, mode));
26 if (mfd != -EINVAL)
27 return mfd;
28
29 mode_compat = mode & ~(MFD_EXEC | MFD_NOEXEC_SEAL);
30
31 if (mode == mode_compat)
32 return mfd;
33
34 return RET_NERRNO(memfd_create(name, mode_compat));
35}
36
4d98709c 37int memfd_new_full(const char *name, unsigned extra_flags) {
7f96b1d8 38 _cleanup_free_ char *g = NULL;
ddeb4241 39
5755381f 40 if (!name) {
caf1436e 41 char pr[TASK_COMM_LEN] = {};
7f96b1d8
LP
42
43 /* If no name is specified we generate one. We include
44 * a hint indicating our library implementation, and
45 * add the thread name to it */
46
47 assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0);
48
49 if (isempty(pr))
50 name = "sd";
51 else {
5755381f
LP
52 _cleanup_free_ char *e = NULL;
53
54 e = utf8_escape_invalid(pr);
55 if (!e)
56 return -ENOMEM;
57
b910cc72 58 g = strjoin("sd-", e);
7f96b1d8
LP
59 if (!g)
60 return -ENOMEM;
61
62 name = g;
63 }
64 }
65
4d98709c
LP
66 return memfd_create_wrapper(
67 name,
68 MFD_CLOEXEC | MFD_NOEXEC_SEAL | extra_flags);
ddeb4241
LP
69}
70
dba777cf 71static int memfd_add_seals(int fd, unsigned seals) {
4d903003
DR
72 assert(fd >= 0);
73
74 return RET_NERRNO(fcntl(fd, F_ADD_SEALS, seals));
75}
76
dba777cf 77static int memfd_get_seals(int fd, unsigned *ret_seals) {
4d903003
DR
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_set_sealed(int fd) {
4d903003 92 return memfd_add_seals(fd, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
ddeb4241
LP
93}
94
fac9c0d5 95int memfd_get_sealed(int fd) {
9ec7d7ae 96 unsigned seals;
a6082d77 97 int r;
ddeb4241 98
4d903003 99 r = memfd_get_seals(fd, &seals);
ddeb4241 100 if (r < 0)
4d903003 101 return r;
ddeb4241 102
17915ea5 103 /* We ignore F_SEAL_EXEC here to support older kernels. */
4d903003 104 return FLAGS_SET(seals, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
ddeb4241
LP
105}
106
d54bbc4c 107int memfd_get_size(int fd, uint64_t *ret) {
a6082d77 108 struct stat stat;
ddeb4241 109
4531a9bc 110 assert(fd >= 0);
d54bbc4c 111 assert(ret);
ddeb4241 112
7c248223 113 if (fstat(fd, &stat) < 0)
ddeb4241
LP
114 return -errno;
115
d54bbc4c 116 *ret = stat.st_size;
5755381f 117 return 0;
ddeb4241
LP
118}
119
fac9c0d5 120int memfd_set_size(int fd, uint64_t sz) {
4531a9bc 121 assert(fd >= 0);
ddeb4241 122
7c248223 123 return RET_NERRNO(ftruncate(fd, sz));
ddeb4241 124}
453a0c29 125
44777d7a
DDM
126int memfd_new_and_seal(const char *name, const void *data, size_t sz) {
127 _cleanup_close_ int fd = -EBADF;
44777d7a
DDM
128 int r;
129
130 assert(data || sz == 0);
131
a87a9625
LP
132 if (sz == SIZE_MAX)
133 sz = strlen(data);
134
4d98709c 135 fd = memfd_new_full(name, MFD_ALLOW_SEALING);
44777d7a
DDM
136 if (fd < 0)
137 return fd;
138
139 if (sz > 0) {
db5381c4 140 ssize_t n = pwrite(fd, data, sz, 0);
44777d7a
DDM
141 if (n < 0)
142 return -errno;
143 if ((size_t) n != sz)
144 return -EIO;
44777d7a
DDM
145 }
146
147 r = memfd_set_sealed(fd);
148 if (r < 0)
149 return r;
150
151 return TAKE_FD(fd);
152}