]>
Commit | Line | Data |
---|---|---|
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 | } |