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