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