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