chiark / gitweb /
selinux: use setcon() instead of reexec to apply selinux policy
[elogind.git] / src / mount-setup.c
index 333107d0be6138f8b754b1e888da6b5c75ec3cc1..290698939e1f876d43197b5f7e9f059bf3811517 100644 (file)
@@ -1,4 +1,4 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
 /***
   This file is part of systemd.
 #include <string.h>
 #include <libgen.h>
 #include <assert.h>
+#include <unistd.h>
+#include <ftw.h>
 
 #include "mount-setup.h"
 #include "log.h"
 #include "macro.h"
 #include "util.h"
+#include "label.h"
+
+#ifndef TTY_GID
+#define TTY_GID 5
+#endif
 
 typedef struct MountPoint {
         const char *what;
@@ -42,13 +49,23 @@ typedef struct MountPoint {
 } MountPoint;
 
 static const MountPoint mount_table[] = {
-        { "proc",        "/proc",                    "proc",        NULL,                MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "sysfs",       "/sys",                     "sysfs",       NULL,                MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "devtmpfs",    "/dev",                     "devtmpfs",    "mode=755",          MS_NOSUID,                    true },
-        { "tmpfs",       "/dev/shm",                 "tmpfs",       "mode=1777",         MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "devpts",      "/dev/pts",                 "devpts",      NULL,                MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
-        { "tmpfs",       "/cgroup",                  "tmpfs",       "mode=755",          MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
-        { "cgroup",      "/cgroup/systemd",          "cgroup",      "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "proc",     "/proc",                  "proc",     NULL,                MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "sysfs",    "/sys",                   "sysfs",    NULL,                MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "devtmpfs", "/dev",                   "devtmpfs", "mode=755",          MS_NOSUID,                    true },
+        { "tmpfs",    "/dev/shm",               "tmpfs",    "mode=1777",         MS_NOSUID|MS_NODEV,           true },
+        { "devpts",   "/dev/pts",               "devpts",   "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, false },
+        { "tmpfs",    "/run",                   "tmpfs",    "mode=755",          MS_NOSUID|MS_NODEV, true },
+        { "tmpfs",    "/sys/fs/cgroup",         "tmpfs",    "mode=755",          MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+        { "cgroup",   "/sys/fs/cgroup/systemd", "cgroup",   "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+};
+
+/* These are API file systems that might be mounted by other software,
+ * we just list them here so that we know that we should ignore them */
+
+static const char * const ignore_paths[] = {
+        "/sys/fs/selinux",
+        "/selinux",
+        "/proc/bus/usb"
 };
 
 bool mount_point_is_api(const char *path) {
@@ -58,10 +75,20 @@ bool mount_point_is_api(const char *path) {
          * should be ignored */
 
         for (i = 0; i < ELEMENTSOF(mount_table); i ++)
-                if (path_startswith(path, mount_table[i].where))
+                if (path_equal(path, mount_table[i].where))
                         return true;
 
-        return path_startswith(path, "/cgroup/");
+        return path_startswith(path, "/sys/fs/cgroup/");
+}
+
+bool mount_point_ignore(const char *path) {
+        unsigned i;
+
+        for (i = 0; i < ELEMENTSOF(ignore_paths); i++)
+                if (path_equal(path, ignore_paths[i]))
+                        return true;
+
+        return false;
 }
 
 static int mount_one(const MountPoint *p) {
@@ -69,6 +96,9 @@ static int mount_one(const MountPoint *p) {
 
         assert(p);
 
+        /* Relabel first, just in case */
+        label_fix(p->where, true);
+
         if ((r = path_is_mount_point(p->where)) < 0)
                 return r;
 
@@ -94,18 +124,23 @@ static int mount_one(const MountPoint *p) {
                 return p->fatal ? -errno : 0;
         }
 
+        /* Relabel again, since we now mounted something fresh here */
+        label_fix(p->where, false);
+
         return 0;
 }
 
 static int mount_cgroup_controllers(void) {
         int r;
         FILE *f;
-        char buf [256];
+        char buf[LINE_MAX];
 
         /* Mount all available cgroup controllers that are built into the kernel. */
 
-        if (!(f = fopen("/proc/cgroups", "re")))
-                return -ENOENT;
+        if (!(f = fopen("/proc/cgroups", "re"))) {
+                log_error("Failed to enumerate cgroup controllers: %m");
+                return 0;
+        }
 
         /* Ignore the header line */
         (void) fgets(buf, sizeof(buf), f);
@@ -113,8 +148,9 @@ static int mount_cgroup_controllers(void) {
         for (;;) {
                 MountPoint p;
                 char *controller, *where;
+                int enabled = false;
 
-                if (fscanf(f, "%ms %*i %*i %*i", &controller) != 1) {
+                if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
 
                         if (feof(f))
                                 break;
@@ -124,7 +160,12 @@ static int mount_cgroup_controllers(void) {
                         goto finish;
                 }
 
-                if (asprintf(&where, "/cgroup/%s", controller) < 0) {
+                if (!enabled) {
+                        free(controller);
+                        continue;
+                }
+
+                if (asprintf(&where, "/sys/fs/cgroup/%s", controller) < 0) {
                         free(controller);
                         r = -ENOMEM;
                         goto finish;
@@ -154,13 +195,83 @@ finish:
         return r;
 }
 
-int mount_setup(void) {
+static int symlink_and_label(const char *old_path, const char *new_path) {
+        int r;
+
+        assert(old_path);
+        assert(new_path);
+
+        if ((r = label_symlinkfile_set(new_path)) < 0)
+                return r;
+
+        if (symlink(old_path, new_path) < 0)
+                r = -errno;
+
+        label_file_clear();
+
+        return r;
+}
+
+static int nftw_cb(
+                const char *fpath,
+                const struct stat *sb,
+                int tflag,
+                struct FTW *ftwbuf) {
+
+        /* No need to label /dev twice in a row... */
+        if (ftwbuf->level == 0)
+                return 0;
+
+        label_fix(fpath, true);
+        return 0;
+};
+
+int mount_setup(bool loaded_policy) {
+
+        const char symlinks[] =
+                "/proc/kcore\0"      "/dev/core\0"
+                "/proc/self/fd\0"    "/dev/fd\0"
+                "/proc/self/fd/0\0"  "/dev/stdin\0"
+                "/proc/self/fd/1\0"  "/dev/stdout\0"
+                "/proc/self/fd/2\0"  "/dev/stderr\0";
+
         int r;
         unsigned i;
+        const char *j, *k;
 
         for (i = 0; i < ELEMENTSOF(mount_table); i ++)
                 if ((r = mount_one(mount_table+i)) < 0)
                         return r;
 
+        /* Nodes in devtmpfs and /run need to be manually updated for
+         * the appropriate labels, after mounting. The other virtual
+         * API file systems like /sys and /proc do not need that, they
+         * use the same label for all their files. */
+        if (loaded_policy) {
+                usec_t before_relabel, after_relabel;
+                char timespan[FORMAT_TIMESPAN_MAX];
+
+                before_relabel = now(CLOCK_MONOTONIC);
+
+                nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS);
+                nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS);
+
+                after_relabel = now(CLOCK_MONOTONIC);
+
+                log_info("Relabelled /dev and /run in %s.",
+                         format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel));
+
+        }
+
+        /* Create a few default symlinks, which are normally created
+         * by udevd, but some scripts might need them before we start
+         * udevd. */
+        NULSTR_FOREACH_PAIR(j, k, symlinks)
+                symlink_and_label(j, k);
+
+        /* Create a few directories we always want around */
+        mkdir("/run/systemd", 0755);
+        mkdir("/run/systemd/system", 0755);
+
         return mount_cgroup_controllers();
 }