]>
Commit | Line | Data |
---|---|---|
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 |
23 | int 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 | 39 | int 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 | 71 | int 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 | 94 | int 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 | 100 | int 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 | 113 | int 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 | 126 | int 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 | 132 | int 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 | |
154 | int 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 | } |