X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fnamespace.c;h=c034bfd161f0a287deb027302fe523dbb0df564b;hp=926ff7133b98e21f881158134817cf88c74b2b89;hb=d3b1c5083359faa6cfca81810cf87ef70d0290f6;hpb=76cd584b8d6e0df5f662f193803ce2bdc530ac86 diff --git a/src/core/namespace.c b/src/core/namespace.c index 926ff7133..c034bfd16 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -39,6 +39,9 @@ #include "missing.h" #include "execute.h" #include "loopback-setup.h" +#include "mkdir.h" +#include "dev-setup.h" +#include "def.h" typedef enum MountMode { /* This is ordered by priority! */ @@ -46,6 +49,7 @@ typedef enum MountMode { READONLY, PRIVATE_TMP, PRIVATE_VAR_TMP, + PRIVATE_DEV, READWRITE } MountMode; @@ -129,6 +133,77 @@ static void drop_duplicates(BindMount *m, unsigned *n) { *n = t - m; } +static int mount_dev(BindMount *m) { + static const char devnodes[] = + "/dev/null\0" + "/dev/zero\0" + "/dev/full\0" + "/dev/random\0" + "/dev/urandom\0" + "/dev/tty\0"; + + struct stat devnodes_stat[6] = {}; + const char *d; + unsigned n = 0; + _cleanup_umask_ mode_t u; + int r; + + assert(m); + + u = umask(0000); + + /* First: record device mode_t and dev_t */ + NULSTR_FOREACH(d, devnodes) { + r = stat(d, &devnodes_stat[n]); + if (r < 0) { + if (errno != ENOENT) + return -errno; + } else { + if (!S_ISBLK(devnodes_stat[n].st_mode) && + !S_ISCHR(devnodes_stat[n].st_mode)) + return -EINVAL; + } + + n++; + } + + assert(n == ELEMENTSOF(devnodes_stat)); + + r = mount("tmpfs", "/dev", "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755"); + if (r < 0) + return m->ignore ? 0 : -errno; + + + mkdir_p("/dev/pts", 0755); + + r = mount("devpts", "/dev/pts", "devpts", MS_NOSUID|MS_NOEXEC, "newinstance,ptmxmode=0666,mode=620,gid=" STRINGIFY(TTY_GID)); + if (r < 0) + return m->ignore ? 0 : -errno; + + mkdir_p("/dev/shm", 0755); + + r = mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID|MS_NODEV|MS_STRICTATIME, "mode=1777"); + if (r < 0) + return m->ignore ? 0 : -errno; + + /* Second: actually create it */ + n = 0; + NULSTR_FOREACH(d, devnodes) { + if (devnodes_stat[n].st_rdev == 0) + continue; + + r = mknod(d, devnodes_stat[n].st_mode, devnodes_stat[n].st_rdev); + if (r < 0) + return m->ignore ? 0 : -errno; + + n++; + } + + dev_setup(NULL); + + return 0; +} + static int apply_mount( BindMount *m, const char *tmp_dir, @@ -141,6 +216,9 @@ static int apply_mount( switch (m->mode) { + case PRIVATE_DEV: + return mount_dev(m); + case INACCESSIBLE: what = "/run/systemd/inaccessible"; break; @@ -194,6 +272,7 @@ int setup_namespace( char** inaccessible_dirs, char* tmp_dir, char* var_tmp_dir, + bool private_dev, unsigned mount_flags) { BindMount *m, *mounts = NULL; @@ -209,7 +288,8 @@ int setup_namespace( n = !!tmp_dir + !!var_tmp_dir + strv_length(read_write_dirs) + strv_length(read_only_dirs) + - strv_length(inaccessible_dirs); + strv_length(inaccessible_dirs) + + private_dev; if (n > 0) { m = mounts = (BindMount *) alloca(n * sizeof(BindMount)); @@ -237,6 +317,12 @@ int setup_namespace( m++; } + if (private_dev) { + m->path = "/dev"; + m->mode = PRIVATE_DEV; + m++; + } + assert(mounts + n == m); qsort(mounts, n, sizeof(BindMount), mount_path_compare); @@ -278,12 +364,22 @@ fail: static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) { _cleanup_free_ char *x = NULL; + char bid[SD_ID128_STRING_MAX]; + sd_id128_t boot_id; + int r; assert(id); assert(prefix); assert(path); - x = strjoin(prefix, "/systemd-", id, "-XXXXXX", NULL); + /* We include the boot id in the directory so that after a + * reboot we can easily identify obsolete directories. */ + + r = sd_id128_get_boot(&boot_id); + if (r < 0) + return r; + + x = strjoin(prefix, "/systemd-private-", sd_id128_to_string(boot_id, bid), "-", id, "-XXXXXX", NULL); if (!x) return -ENOMEM;