Line data Source code
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/mman.h>
25 : #include <sys/prctl.h>
26 :
27 : #ifdef HAVE_LINUX_MEMFD_H
28 : # include <linux/memfd.h>
29 : #endif
30 :
31 : #include "util.h"
32 : #include "memfd-util.h"
33 : #include "utf8.h"
34 : #include "missing.h"
35 :
36 49 : int memfd_new(const char *name) {
37 99 : _cleanup_free_ char *g = NULL;
38 : int fd;
39 :
40 49 : if (!name) {
41 4 : char pr[17] = {};
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 4 : assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0);
48 :
49 4 : if (isempty(pr))
50 0 : name = "sd";
51 : else {
52 8 : _cleanup_free_ char *e = NULL;
53 :
54 4 : e = utf8_escape_invalid(pr);
55 4 : if (!e)
56 0 : return -ENOMEM;
57 :
58 4 : g = strappend("sd-", e);
59 4 : if (!g)
60 0 : return -ENOMEM;
61 :
62 4 : name = g;
63 : }
64 : }
65 :
66 49 : fd = memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
67 50 : if (fd < 0)
68 0 : return -errno;
69 :
70 50 : return fd;
71 : }
72 :
73 3 : int memfd_map(int fd, uint64_t offset, size_t size, void **p) {
74 : void *q;
75 : int sealed;
76 :
77 3 : assert(fd >= 0);
78 3 : assert(size > 0);
79 3 : assert(p);
80 :
81 3 : sealed = memfd_get_sealed(fd);
82 3 : if (sealed < 0)
83 0 : return sealed;
84 :
85 3 : if (sealed)
86 0 : q = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset);
87 : else
88 3 : q = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
89 :
90 3 : if (q == MAP_FAILED)
91 0 : return -errno;
92 :
93 3 : *p = q;
94 3 : return 0;
95 : }
96 :
97 4 : int memfd_set_sealed(int fd) {
98 : int r;
99 :
100 4 : assert(fd >= 0);
101 :
102 4 : r = fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
103 4 : if (r < 0)
104 0 : return -errno;
105 :
106 4 : return 0;
107 : }
108 :
109 3 : int memfd_get_sealed(int fd) {
110 : int r;
111 :
112 3 : assert(fd >= 0);
113 :
114 3 : r = fcntl(fd, F_GET_SEALS);
115 3 : if (r < 0)
116 0 : return -errno;
117 :
118 3 : return r == (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
119 : }
120 :
121 5 : int memfd_get_size(int fd, uint64_t *sz) {
122 : struct stat stat;
123 : int r;
124 :
125 5 : assert(fd >= 0);
126 5 : assert(sz);
127 :
128 5 : r = fstat(fd, &stat);
129 5 : if (r < 0)
130 0 : return -errno;
131 :
132 5 : *sz = stat.st_size;
133 5 : return 0;
134 : }
135 :
136 48 : int memfd_set_size(int fd, uint64_t sz) {
137 : int r;
138 :
139 48 : assert(fd >= 0);
140 :
141 48 : r = ftruncate(fd, sz);
142 49 : if (r < 0)
143 0 : return -errno;
144 :
145 49 : return 0;
146 : }
147 :
148 3 : int memfd_new_and_map(const char *name, size_t sz, void **p) {
149 6 : _cleanup_close_ int fd = -1;
150 : int r;
151 :
152 3 : assert(sz > 0);
153 3 : assert(p);
154 :
155 3 : fd = memfd_new(name);
156 3 : if (fd < 0)
157 0 : return fd;
158 :
159 3 : r = memfd_set_size(fd, sz);
160 3 : if (r < 0)
161 0 : return r;
162 :
163 3 : r = memfd_map(fd, 0, sz, p);
164 3 : if (r < 0)
165 0 : return r;
166 :
167 3 : r = fd;
168 3 : fd = -1;
169 :
170 3 : return r;
171 : }
|