]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/mount-setup.c
udev: add SECLABEL{selinux}= support
[thirdparty/systemd.git] / src / core / mount-setup.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
8e274523
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
8e274523
LP
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
5430f7f2 16 Lesser General Public License for more details.
8e274523 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
8e274523
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/mount.h>
23#include <errno.h>
24#include <sys/stat.h>
25#include <stdlib.h>
26#include <string.h>
27#include <libgen.h>
28#include <assert.h>
5c0532d1 29#include <unistd.h>
1829dc9d 30#include <ftw.h>
8e274523
LP
31
32#include "mount-setup.h"
5ba2dc25 33#include "dev-setup.h"
8e274523 34#include "log.h"
c9af1080
LP
35#include "macro.h"
36#include "util.h"
5275d3c1 37#include "label.h"
0c85a4f3
LP
38#include "set.h"
39#include "strv.h"
49e942b2 40#include "mkdir.h"
9eb977db 41#include "path-util.h"
48ac500b 42#include "missing.h"
c481f78b 43#include "virt.h"
34e5a31e 44#include "efivars.h"
8e274523 45
bef2733f
LP
46#ifndef TTY_GID
47#define TTY_GID 5
48#endif
49
6aa220e0
KS
50typedef enum MountMode {
51 MNT_NONE = 0,
52 MNT_FATAL = 1 << 0,
53 MNT_IN_CONTAINER = 1 << 1,
54} MountMode;
55
ca714c0e
LP
56typedef struct MountPoint {
57 const char *what;
58 const char *where;
59 const char *type;
60 const char *options;
61 unsigned long flags;
6aa220e0
KS
62 bool (*condition_fn)(void);
63 MountMode mode;
ca714c0e
LP
64} MountPoint;
65
4ef31082 66/* The first three entries we might need before SELinux is up. The
160481f6
RS
67 * fourth (securityfs) is needed by IMA to load a custom policy. The
68 * other ones we can delay until SELinux and IMA are loaded. */
ffbd2c4d 69#define N_EARLY_MOUNT 5
4ef31082 70
ca714c0e 71static const MountPoint mount_table[] = {
6aa220e0
KS
72 { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
73 NULL, MNT_FATAL|MNT_IN_CONTAINER },
74 { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
75 NULL, MNT_FATAL|MNT_IN_CONTAINER },
76 { "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME,
77 NULL, MNT_FATAL|MNT_IN_CONTAINER },
78 { "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
79 NULL, MNT_NONE },
ffbd2c4d
NC
80 { "smackfs", "/sys/fs/smackfs", "smackfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
81 NULL, MNT_NONE },
d407c940
AK
82#ifdef HAVE_SMACK
83 { "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
84 NULL, MNT_IN_CONTAINER },
85#endif
6aa220e0
KS
86 { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
87 NULL, MNT_FATAL|MNT_IN_CONTAINER },
88 { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
89 NULL, MNT_IN_CONTAINER },
d407c940
AK
90#ifdef HAVE_SMACK
91 { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
92 NULL, MNT_IN_CONTAINER },
93#endif
6aa220e0
KS
94 { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
95 NULL, MNT_FATAL|MNT_IN_CONTAINER },
96 { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
97 NULL, MNT_IN_CONTAINER },
0ee67958
ZJS
98#ifdef HAVE_XATTR
99 { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
100 NULL, MNT_IN_CONTAINER },
101#endif
102 { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
6aa220e0 103 NULL, MNT_IN_CONTAINER },
c06bf414
KS
104 { "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
105 NULL, MNT_NONE },
106#ifdef ENABLE_EFI
107 { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
108 is_efi_boot, MNT_NONE },
109#endif
8e274523
LP
110};
111
949c6510 112/* These are API file systems that might be mounted by other software,
46ff0ed7 113 * we just list them here so that we know that we should ignore them */
949c6510 114
eaeb18db
LP
115static const char ignore_paths[] =
116 /* SELinux file systems */
117 "/sys/fs/selinux\0"
118 "/selinux\0"
119 /* Legacy cgroup mount points */
120 "/dev/cgroup\0"
121 "/cgroup\0"
122 /* Legacy kernel file system */
123 "/proc/bus/usb\0"
124 /* Container bind mounts */
125 "/proc/sys\0"
126 "/dev/console\0"
c481f78b 127 "/proc/kmsg\0";
949c6510 128
dad08730
LP
129bool mount_point_is_api(const char *path) {
130 unsigned i;
131
132 /* Checks if this mount point is considered "API", and hence
133 * should be ignored */
134
ca714c0e 135 for (i = 0; i < ELEMENTSOF(mount_table); i ++)
449ddb2d 136 if (path_equal(path, mount_table[i].where))
dad08730
LP
137 return true;
138
57f2a956
KS
139 return path_startswith(path, "/sys/fs/cgroup/");
140}
141
142bool mount_point_ignore(const char *path) {
eaeb18db 143 const char *i;
57f2a956 144
eaeb18db
LP
145 NULSTR_FOREACH(i, ignore_paths)
146 if (path_equal(path, i))
949c6510
LP
147 return true;
148
57f2a956 149 return false;
dad08730
LP
150}
151
4ef31082 152static int mount_one(const MountPoint *p, bool relabel) {
8e274523
LP
153 int r;
154
ca714c0e 155 assert(p);
8e274523 156
6aa220e0
KS
157 if (p->condition_fn && !p->condition_fn())
158 return 0;
159
51b4af2c 160 /* Relabel first, just in case */
4ef31082 161 if (relabel)
c9bc0764 162 label_fix(p->where, true, true);
51b4af2c 163
c481f78b
LP
164 r = path_is_mount_point(p->where, true);
165 if (r < 0)
8e274523
LP
166 return r;
167
168 if (r > 0)
51b4af2c 169 return 0;
8e274523 170
c481f78b 171 /* Skip securityfs in a container */
6aa220e0 172 if (!(p->mode & MNT_IN_CONTAINER) && detect_container(NULL) > 0)
c481f78b
LP
173 return 0;
174
a04f58d6
LP
175 /* The access mode here doesn't really matter too much, since
176 * the mounted file system will take precedence anyway. */
d2e54fae 177 mkdir_p_label(p->where, 0755);
a04f58d6 178
8e274523 179 log_debug("Mounting %s to %s of type %s with options %s.",
ca714c0e
LP
180 p->what,
181 p->where,
182 p->type,
183 strna(p->options));
184
185 if (mount(p->what,
186 p->where,
187 p->type,
188 p->flags,
189 p->options) < 0) {
6aa220e0
KS
190 log_full((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, "Failed to mount %s: %s", p->where, strerror(errno));
191 return (p->mode & MNT_FATAL) ? -errno : 0;
8e274523
LP
192 }
193
51b4af2c 194 /* Relabel again, since we now mounted something fresh here */
4ef31082 195 if (relabel)
c9bc0764 196 label_fix(p->where, false, false);
5275d3c1 197
0c85a4f3 198 return 1;
8e274523
LP
199}
200
4ef31082
LP
201int mount_setup_early(void) {
202 unsigned i;
203 int r = 0;
204
205 assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
206
207 /* Do a minimal mount of /proc and friends to enable the most
208 * basic stuff, such as SELinux */
209 for (i = 0; i < N_EARLY_MOUNT; i ++) {
210 int j;
211
212 j = mount_one(mount_table + i, false);
213 if (r == 0)
214 r = j;
215 }
216
217 return r;
218}
219
0c85a4f3 220int mount_cgroup_controllers(char ***join_controllers) {
2076ca54 221 int r;
20c03b7b 222 char buf[LINE_MAX];
a6b26d90
ZJS
223 _cleanup_set_free_free_ Set *controllers = NULL;
224 _cleanup_fclose_ FILE *f;
2076ca54 225
670802d4 226 /* Mount all available cgroup controllers that are built into the kernel. */
2076ca54 227
0c85a4f3
LP
228 f = fopen("/proc/cgroups", "re");
229 if (!f) {
016e9849
LP
230 log_error("Failed to enumerate cgroup controllers: %m");
231 return 0;
232 }
2076ca54 233
0c85a4f3 234 controllers = set_new(string_hash_func, string_compare_func);
a6b26d90
ZJS
235 if (!controllers)
236 return log_oom();
0c85a4f3 237
2076ca54 238 /* Ignore the header line */
bab45044 239 (void) fgets(buf, sizeof(buf), f);
2076ca54
LP
240
241 for (;;) {
0c85a4f3
LP
242 char *controller;
243 int enabled = 0;
2076ca54 244
16f6682d 245 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
2076ca54
LP
246
247 if (feof(f))
248 break;
249
250 log_error("Failed to parse /proc/cgroups.");
a6b26d90 251 return -EIO;
2076ca54
LP
252 }
253
600a328f
LP
254 if (!enabled) {
255 free(controller);
256 continue;
257 }
258
ef42202a 259 r = set_consume(controllers, controller);
0c85a4f3
LP
260 if (r < 0) {
261 log_error("Failed to add controller to set.");
a6b26d90 262 return r;
0c85a4f3
LP
263 }
264 }
265
266 for (;;) {
a6b26d90
ZJS
267 MountPoint p = {
268 .what = "cgroup",
269 .type = "cgroup",
270 .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
271 .mode = MNT_IN_CONTAINER,
272 };
0c85a4f3 273 char ***k = NULL;
a6b26d90 274 _cleanup_free_ char *options = NULL, *controller;
0c85a4f3
LP
275
276 controller = set_steal_first(controllers);
277 if (!controller)
278 break;
279
280 if (join_controllers)
281 for (k = join_controllers; *k; k++)
282 if (strv_find(*k, controller))
283 break;
284
285 if (k && *k) {
286 char **i, **j;
287
288 for (i = *k, j = *k; *i; i++) {
289
290 if (!streq(*i, controller)) {
a6b26d90 291 char _cleanup_free_ *t;
0c85a4f3
LP
292
293 t = set_remove(controllers, *i);
294 if (!t) {
295 free(*i);
296 continue;
297 }
0c85a4f3
LP
298 }
299
300 *(j++) = *i;
301 }
302
303 *j = NULL;
304
305 options = strv_join(*k, ",");
a6b26d90
ZJS
306 if (!options)
307 return log_oom();
0c85a4f3
LP
308 } else {
309 options = controller;
310 controller = NULL;
311 }
312
a6b26d90 313 p.where = strappenda("/sys/fs/cgroup/", options);
0c85a4f3 314 p.options = options;
2076ca54 315
4ef31082 316 r = mount_one(&p, true);
a6b26d90
ZJS
317 if (r < 0)
318 return r;
0c85a4f3
LP
319
320 if (r > 0 && k && *k) {
321 char **i;
322
323 for (i = *k; *i; i++) {
a6b26d90 324 char *t = strappenda("/sys/fs/cgroup/", *i);
0c85a4f3
LP
325
326 r = symlink(options, t);
0c85a4f3 327 if (r < 0 && errno != EEXIST) {
c79bb9e4 328 log_error("Failed to create symlink %s: %m", t);
a6b26d90 329 return -errno;
0c85a4f3
LP
330 }
331 }
332 }
2076ca54
LP
333 }
334
a6b26d90 335 return 0;
2076ca54
LP
336}
337
1829dc9d
LP
338static int nftw_cb(
339 const char *fpath,
340 const struct stat *sb,
341 int tflag,
342 struct FTW *ftwbuf) {
343
9fe117ea 344 /* No need to label /dev twice in a row... */
edb49778
LP
345 if (_unlikely_(ftwbuf->level == 0))
346 return FTW_CONTINUE;
347
c9bc0764 348 label_fix(fpath, false, false);
af65c248 349
edb49778 350 /* /run/initramfs is static data and big, no need to
af65c248 351 * dynamically relabel its contents at boot... */
edb49778
LP
352 if (_unlikely_(ftwbuf->level == 1 &&
353 tflag == FTW_D &&
354 streq(fpath, "/run/initramfs")))
355 return FTW_SKIP_SUBTREE;
9fe117ea 356
edb49778 357 return FTW_CONTINUE;
1829dc9d
LP
358};
359
0b3325e7 360int mount_setup(bool loaded_policy) {
8e274523 361 int r;
dad08730 362 unsigned i;
8e274523 363
4ef31082
LP
364 for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
365 r = mount_one(mount_table + i, true);
366
367 if (r < 0)
8e274523 368 return r;
4ef31082 369 }
8e274523 370
f1d19aa4
LP
371 /* Nodes in devtmpfs and /run need to be manually updated for
372 * the appropriate labels, after mounting. The other virtual
373 * API file systems like /sys and /proc do not need that, they
374 * use the same label for all their files. */
0b3325e7
LP
375 if (loaded_policy) {
376 usec_t before_relabel, after_relabel;
377 char timespan[FORMAT_TIMESPAN_MAX];
378
379 before_relabel = now(CLOCK_MONOTONIC);
380
edb49778
LP
381 nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
382 nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
0b3325e7
LP
383
384 after_relabel = now(CLOCK_MONOTONIC);
385
386 log_info("Relabelled /dev and /run in %s.",
2fa4092c 387 format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0));
3bbecb2f 388 }
1829dc9d 389
5c0532d1 390 /* Create a few default symlinks, which are normally created
f1d19aa4 391 * by udevd, but some scripts might need them before we start
5c0532d1 392 * udevd. */
01ed0e23 393 dev_setup(NULL);
5c0532d1 394
b3ac5f8c
LP
395 /* Mark the root directory as shared in regards to mount
396 * propagation. The kernel defaults to "private", but we think
397 * it makes more sense to have a default of "shared" so that
398 * nspawn and the container tools work out of the box. If
399 * specific setups need other settings they can reset the
400 * propagation mode to private if needed. */
c481f78b
LP
401 if (detect_container(NULL) <= 0)
402 if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
403 log_warning("Failed to set up the root directory for shared mount propagation: %m");
b3ac5f8c 404
66e41181
LP
405 /* Create a few directories we always want around, Note that
406 * sd_booted() checks for /run/systemd/system, so this mkdir
407 * really needs to stay for good, otherwise software that
408 * copied sd-daemon.c into their sources will misdetect
409 * systemd. */
d2e54fae
KS
410 mkdir_label("/run/systemd", 0755);
411 mkdir_label("/run/systemd/system", 0755);
c17ec25e 412 mkdir_label("/run/systemd/inaccessible", 0000);
b925e726 413
0c85a4f3 414 return 0;
8e274523 415}