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