chiark / gitweb /
mac: also rename use_{smack,selinux,apparmor}() calls so that they share the new...
[elogind.git] / src / shared / memfd.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <sys/ioctl.h>
25 #include <sys/mman.h>
26 #include <sys/prctl.h>
27
28 #ifdef HAVE_LINUX_MEMFD_H
29 #  include <linux/memfd.h>
30 #endif
31
32 #include "util.h"
33 #include "bus-label.h"
34 #include "memfd.h"
35 #include "utf8.h"
36 #include "missing.h"
37
38 int memfd_new(const char *name) {
39         _cleanup_free_ char *g = NULL;
40         int fd;
41
42         if (!name) {
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 {
54                         _cleanup_free_ char *e = NULL;
55
56                         e = utf8_escape_invalid(pr);
57                         if (!e)
58                                 return -ENOMEM;
59
60                         g = strappend("sd-", e);
61                         if (!g)
62                                 return -ENOMEM;
63
64                         name = g;
65                 }
66         }
67
68         fd = memfd_create(name, MFD_ALLOW_SEALING);
69         if (fd < 0)
70                 return -errno;
71
72         return fd;
73 }
74
75 int memfd_map(int fd, uint64_t offset, size_t size, void **p) {
76         void *q;
77         int sealed;
78
79         assert(fd >= 0);
80         assert(size > 0);
81         assert(p);
82
83         sealed = memfd_get_sealed(fd);
84         if (sealed < 0)
85                 return sealed;
86
87         if (sealed)
88                 q = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset);
89         else
90                 q = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
91
92         if (q == MAP_FAILED)
93                 return -errno;
94
95         *p = q;
96         return 0;
97 }
98
99 int memfd_set_sealed(int fd) {
100         int r;
101
102         assert(fd >= 0);
103
104         r = fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
105         if (r < 0)
106                 return -errno;
107
108         return 0;
109 }
110
111 int memfd_get_sealed(int fd) {
112         int r;
113
114         assert(fd >= 0);
115
116         r = fcntl(fd, F_GET_SEALS);
117         if (r < 0)
118                 return -errno;
119
120         return (r & (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)) ==
121                     (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
122 }
123
124 int memfd_get_size(int fd, uint64_t *sz) {
125         struct stat stat;
126         int r;
127
128         assert(fd >= 0);
129         assert(sz);
130
131         r = fstat(fd, &stat);
132         if (r < 0)
133                 return -errno;
134
135         *sz = stat.st_size;
136         return 0;
137 }
138
139 int memfd_set_size(int fd, uint64_t sz) {
140         int r;
141
142         assert(fd >= 0);
143
144         r = ftruncate(fd, sz);
145         if (r < 0)
146                 return -errno;
147
148         return 0;
149 }
150
151 int memfd_new_and_map(const char *name, size_t sz, void **p) {
152         _cleanup_close_ int fd = -1;
153         int r;
154
155         assert(sz > 0);
156         assert(p);
157
158         fd = memfd_new(name);
159         if (fd < 0)
160                 return fd;
161
162         r = memfd_set_size(fd, sz);
163         if (r < 0)
164                 return r;
165
166         r = memfd_map(fd, 0, sz, p);
167         if (r < 0)
168                 return r;
169
170         r = fd;
171         fd = -1;
172
173         return r;
174 }
175
176 int memfd_get_name(int fd, char **name) {
177         char path[sizeof("/proc/self/fd/") + DECIMAL_STR_MAX(int)], buf[FILENAME_MAX+1], *e;
178         const char *delim, *end;
179         _cleanup_free_ char *n = NULL;
180         ssize_t k;
181
182         assert(fd >= 0);
183         assert(name);
184
185         sprintf(path, "/proc/self/fd/%i", fd);
186
187         k = readlink(path, buf, sizeof(buf));
188         if (k < 0)
189                 return -errno;
190
191         if ((size_t) k >= sizeof(buf))
192                 return -E2BIG;
193
194         buf[k] = 0;
195
196         delim = strstr(buf, ":[");
197         if (!delim)
198                 return -EIO;
199
200         delim = strchr(delim + 2, ':');
201         if (!delim)
202                 return -EIO;
203
204         delim++;
205
206         end = strchr(delim, ']');
207         if (!end)
208                 return -EIO;
209
210         n = strndup(delim, end - delim);
211         if (!n)
212                 return -ENOMEM;
213
214         e = utf8_escape_invalid(n);
215         if (!e)
216                 return -ENOMEM;
217
218         *name = e;
219
220         return 0;
221 }