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