]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/memfd-util.c
3257c1b9dd4b0c8fbdbf962fc183fb75b8c3dd0e
[thirdparty/systemd.git] / src / basic / memfd-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <sched.h>
4 #include <stdio.h>
5 #include <sys/prctl.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8
9 #include "alloc-util.h"
10 #include "errno-util.h"
11 #include "fd-util.h"
12 #include "memfd-util.h"
13 #include "string-util.h"
14 #include "utf8.h"
15
16 int memfd_create_wrapper(const char *name, unsigned mode) {
17 unsigned mode_compat;
18 int mfd;
19
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
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
37 int memfd_new_full(const char *name, unsigned extra_flags) {
38 _cleanup_free_ char *g = NULL;
39
40 if (!name) {
41 char pr[TASK_COMM_LEN] = {};
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 {
52 _cleanup_free_ char *e = NULL;
53
54 e = utf8_escape_invalid(pr);
55 if (!e)
56 return -ENOMEM;
57
58 g = strjoin("sd-", e);
59 if (!g)
60 return -ENOMEM;
61
62 name = g;
63 }
64 }
65
66 return memfd_create_wrapper(
67 name,
68 MFD_CLOEXEC | MFD_NOEXEC_SEAL | extra_flags);
69 }
70
71 static int memfd_add_seals(int fd, unsigned seals) {
72 assert(fd >= 0);
73
74 return RET_NERRNO(fcntl(fd, F_ADD_SEALS, seals));
75 }
76
77 static int memfd_get_seals(int fd, unsigned *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
91 int memfd_set_sealed(int fd) {
92 return memfd_add_seals(fd, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
93 }
94
95 int memfd_get_sealed(int fd) {
96 unsigned seals;
97 int r;
98
99 r = memfd_get_seals(fd, &seals);
100 if (r < 0)
101 return r;
102
103 /* We ignore F_SEAL_EXEC here to support older kernels. */
104 return FLAGS_SET(seals, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
105 }
106
107 int memfd_get_size(int fd, uint64_t *ret) {
108 struct stat stat;
109
110 assert(fd >= 0);
111 assert(ret);
112
113 if (fstat(fd, &stat) < 0)
114 return -errno;
115
116 *ret = stat.st_size;
117 return 0;
118 }
119
120 int memfd_set_size(int fd, uint64_t sz) {
121 assert(fd >= 0);
122
123 return RET_NERRNO(ftruncate(fd, sz));
124 }
125
126 int memfd_new_and_seal(const char *name, const void *data, size_t sz) {
127 _cleanup_close_ int fd = -EBADF;
128 int r;
129
130 assert(data || sz == 0);
131
132 if (sz == SIZE_MAX)
133 sz = strlen(data);
134
135 fd = memfd_new_full(name, MFD_ALLOW_SEALING);
136 if (fd < 0)
137 return fd;
138
139 if (sz > 0) {
140 ssize_t n = pwrite(fd, data, sz, 0);
141 if (n < 0)
142 return -errno;
143 if ((size_t) n != sz)
144 return -EIO;
145 }
146
147 r = memfd_set_sealed(fd);
148 if (r < 0)
149 return r;
150
151 return TAKE_FD(fd);
152 }