]>
Commit | Line | Data |
---|---|---|
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 |
16 | int 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 | 37 | int 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 | 71 | static 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 | 77 | static 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 | 91 | int 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 | 95 | int 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 | 107 | int 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 | 120 | int 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 |
126 | int 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 | } |