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