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