Esempio n. 1
0
int fdset_steal_first(FDSet *fds) {
        void *p;

        p = set_steal_first(MAKE_SET(fds));
        if (!p)
                return -ENOENT;

        return PTR_TO_FD(p);
}
Esempio n. 2
0
DnsTransaction* dns_transaction_free(DnsTransaction *t) {
        DnsQuery *q;
        DnsZoneItem *i;

        if (!t)
                return NULL;

        sd_event_source_unref(t->timeout_event_source);

        dns_packet_unref(t->sent);
        dns_packet_unref(t->received);
        dns_answer_unref(t->cached);

        sd_event_source_unref(t->dns_udp_event_source);
        safe_close(t->dns_udp_fd);

        dns_server_unref(t->server);
        dns_stream_free(t->stream);

        if (t->scope) {
                hashmap_remove(t->scope->transactions, t->key);

                if (t->id != 0)
                        hashmap_remove(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id));
        }

        dns_resource_key_unref(t->key);

        while ((q = set_steal_first(t->queries)))
                set_remove(q->transactions, t);
        set_free(t->queries);

        while ((i = set_steal_first(t->zone_items)))
                i->probe_transaction = NULL;
        set_free(t->zone_items);

        free(t);
        return NULL;
}
Esempio n. 3
0
static void context_free(Context *context) {
        sd_event_source *es;
        Connection *c;

        assert(context);

        while ((es = set_steal_first(context->listen)))
                sd_event_source_unref(es);

        while ((c = set_first(context->connections)))
                connection_free(c);

        set_free(context->listen);
        set_free(context->connections);
}
Esempio n. 4
0
int automount_send_ready(Automount *a, int status) {
        int ioctl_fd, r;
        unsigned token;

        assert(a);
        assert(status <= 0);

        if (set_isempty(a->tokens))
                return 0;

        ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
        if (ioctl_fd < 0) {
                r = ioctl_fd;
                goto fail;
        }

        if (status)
                log_debug_unit(UNIT(a)->id, "Sending failure: %s", strerror(-status));
        else
                log_debug_unit(UNIT(a)->id, "Sending success.");

        r = 0;

        /* Autofs thankfully does not hand out 0 as a token */
        while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) {
                int k;

                /* Autofs fun fact II:
                 *
                 * if you pass a positive status code here, the kernel will
                 * freeze! Yay! */

                k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
                                      ioctl_fd,
                                      token,
                                      status);
                if (k < 0)
                        r = k;
        }

fail:
        if (ioctl_fd >= 0)
                close_nointr_nofail(ioctl_fd);

        return r;
}
Esempio n. 5
0
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
        char *node;

        assert(i);
        assert(prefix);

        while ((node = set_steal_first(s))) {
                const char *e;

                e = object_path_startswith(node, prefix);
                if (e && e[0])
                        fprintf(i->f, " <node name=\"%s\"/>\n", e);

                free(node);
        }

        return 0;
}
Esempio n. 6
0
void manager_etc_hosts_flush(Manager *m) {
        EtcHostsItem *item;
        EtcHostsItemByName *bn;

        while ((item = set_steal_first(m->etc_hosts_by_address))) {
                strv_free(item->names);
                free(item);
        }

        while ((bn = hashmap_steal_first(m->etc_hosts_by_name))) {
                free(bn->name);
                free(bn->items);
                free(bn);
        }

        m->etc_hosts_by_address = set_free(m->etc_hosts_by_address);
        m->etc_hosts_by_name = hashmap_free(m->etc_hosts_by_name);

        m->etc_hosts_mtime = USEC_INFINITY;
}
Esempio n. 7
0
static int automount_send_ready(Automount *a, Set *tokens, int status) {
        _cleanup_close_ int ioctl_fd = -1;
        unsigned token;
        int r;

        assert(a);
        assert(status <= 0);

        if (set_isempty(tokens))
                return 0;

        ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
        if (ioctl_fd < 0)
                return ioctl_fd;

        if (status != 0)
                log_unit_debug_errno(UNIT(a), status, "Sending failure: %m");
        else
                log_unit_debug(UNIT(a), "Sending success.");

        r = 0;

        /* Autofs thankfully does not hand out 0 as a token */
        while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
                int k;

                /* Autofs fun fact II:
                 *
                 * if you pass a positive status code here, the kernel will
                 * freeze! Yay! */

                k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
                                      ioctl_fd,
                                      token,
                                      status);
                if (k < 0)
                        r = k;
        }

        return r;
}
Esempio n. 8
0
void fdset_free(FDSet *s) {
        void *p;

        while ((p = set_steal_first(MAKE_SET(s)))) {
                /* Valgrind's fd might have ended up in this set here,
                 * due to fdset_new_fill(). We'll ignore all failures
                 * here, so that the EBADFD that valgrind will return
                 * us on close() doesn't influence us */

                /* When reloading duplicates of the private bus
                 * connection fds and suchlike are closed here, which
                 * has no effect at all, since they are only
                 * duplicates. So don't be surprised about these log
                 * messages. */

                log_debug("Closing left-over fd %i", PTR_TO_FD(p));
                close_nointr(PTR_TO_FD(p));
        }

        set_free(MAKE_SET(s));
}
Esempio n. 9
0
int mount_cgroup_controllers(char ***join_controllers) {
        int r;
        FILE *f;
        char buf[LINE_MAX];
        Set *controllers;

        /* Mount all available cgroup controllers that are built into the kernel. */

        f = fopen("/proc/cgroups", "re");
        if (!f) {
                log_error("Failed to enumerate cgroup controllers: %m");
                return 0;
        }

        controllers = set_new(string_hash_func, string_compare_func);
        if (!controllers) {
                r = log_oom();
                goto finish;
        }

        /* Ignore the header line */
        (void) fgets(buf, sizeof(buf), f);

        for (;;) {
                char *controller;
                int enabled = 0;

                if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {

                        if (feof(f))
                                break;

                        log_error("Failed to parse /proc/cgroups.");
                        r = -EIO;
                        goto finish;
                }

                if (!enabled) {
                        free(controller);
                        continue;
                }

                r = set_put(controllers, controller);
                if (r < 0) {
                        log_error("Failed to add controller to set.");
                        free(controller);
                        goto finish;
                }
        }

        for (;;) {
                MountPoint p;
                char *controller, *where, *options;
                char ***k = NULL;

                controller = set_steal_first(controllers);
                if (!controller)
                        break;

                if (join_controllers)
                        for (k = join_controllers; *k; k++)
                                if (strv_find(*k, controller))
                                        break;

                if (k && *k) {
                        char **i, **j;

                        for (i = *k, j = *k; *i; i++) {

                                if (!streq(*i, controller)) {
                                        char *t;

                                        t = set_remove(controllers, *i);
                                        if (!t) {
                                                free(*i);
                                                continue;
                                        }
                                        free(t);
                                }

                                *(j++) = *i;
                        }

                        *j = NULL;

                        options = strv_join(*k, ",");
                        if (!options) {
                                free(controller);
                                r = log_oom();
                                goto finish;
                        }

                } else {
                        options = controller;
                        controller = NULL;
                }

                where = strappend("/sys/fs/cgroup/", options);
                if (!where) {
                        free(options);
                        r = log_oom();
                        goto finish;
                }

                zero(p);
                p.what = "cgroup";
                p.where = where;
                p.type = "cgroup";
                p.options = options;
                p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV;
                p.mode = MNT_IN_CONTAINER;

                r = mount_one(&p, true);
                free(controller);
                free(where);

                if (r < 0) {
                        free(options);
                        goto finish;
                }

                if (r > 0 && k && *k) {
                        char **i;

                        for (i = *k; *i; i++) {
                                char *t;

                                t = strappend("/sys/fs/cgroup/", *i);
                                if (!t) {
                                        r = log_oom();
                                        free(options);
                                        goto finish;
                                }

                                r = symlink(options, t);
                                free(t);

                                if (r < 0 && errno != EEXIST) {
                                        log_error("Failed to create symlink: %m");
                                        r = -errno;
                                        free(options);
                                        goto finish;
                                }
                        }
                }

                free(options);
        }

        r = 0;

finish:
        set_free_free(controllers);

        fclose(f);

        return r;
}
Esempio n. 10
0
int mount_cgroup_controllers(char ***join_controllers) {
        _cleanup_set_free_free_ Set *controllers = NULL;
        int r;

        if (!cg_is_legacy_wanted())
                return 0;

        /* Mount all available cgroup controllers that are built into the kernel. */

        controllers = set_new(&string_hash_ops);
        if (!controllers)
                return log_oom();

        r = cg_kernel_controllers(controllers);
        if (r < 0)
                return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");

        for (;;) {
                _cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL;
                MountPoint p = {
                        .what = "cgroup",
                        .type = "cgroup",
                        .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
                        .mode = MNT_IN_CONTAINER,
                };
                char ***k = NULL;

                controller = set_steal_first(controllers);
                if (!controller)
                        break;

                if (join_controllers)
                        for (k = join_controllers; *k; k++)
                                if (strv_find(*k, controller))
                                        break;

                if (k && *k) {
                        char **i, **j;

                        for (i = *k, j = *k; *i; i++) {

                                if (!streq(*i, controller)) {
                                        _cleanup_free_ char *t;

                                        t = set_remove(controllers, *i);
                                        if (!t) {
                                                free(*i);
                                                continue;
                                        }
                                }

                                *(j++) = *i;
                        }

                        *j = NULL;

                        options = strv_join(*k, ",");
                        if (!options)
                                return log_oom();
                } else {
                        options = controller;
                        controller = NULL;
                }

                where = strappend("/sys/fs/cgroup/", options);
                if (!where)
                        return log_oom();

                p.where = where;
                p.options = options;

                r = mount_one(&p, true);
                if (r < 0)
                        return r;

                if (r > 0 && k && *k) {
                        char **i;

                        for (i = *k; *i; i++) {
                                _cleanup_free_ char *t = NULL;

                                t = strappend("/sys/fs/cgroup/", *i);
                                if (!t)
                                        return log_oom();

                                r = symlink(options, t);
                                if (r < 0 && errno != EEXIST)
                                        return log_error_errno(errno, "Failed to create symlink %s: %m", t);
#ifdef SMACK_RUN_LABEL
                                r = mac_smack_copy(t, options);
                                if (r < 0 && r != -EOPNOTSUPP)
                                        return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", options, t);
#endif
                        }
                }
        }

        /* Now that we mounted everything, let's make the tmpfs the
         * cgroup file systems are mounted into read-only. */
        (void) mount("tmpfs", "/sys/fs/cgroup", "tmpfs", MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");

        return 0;
}

#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
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 (_unlikely_(ftwbuf->level == 0))
                return FTW_CONTINUE;

        label_fix(fpath, false, false);

        /* /run/initramfs is static data and big, no need to
         * dynamically relabel its contents at boot... */
        if (_unlikely_(ftwbuf->level == 1 &&
                      tflag == FTW_D &&
                      streq(fpath, "/run/initramfs")))
                return FTW_SKIP_SUBTREE;

        return FTW_CONTINUE;
};
#endif

int mount_setup(bool loaded_policy) {
        unsigned i;
        int r = 0;

        for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
                int j;

                j = mount_one(mount_table + i, loaded_policy);
                if (j != 0 && r >= 0)
                        r = j;
        }

        if (r < 0)
                return r;

#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
        /* 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|FTW_ACTIONRETVAL);
                nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);

                after_relabel = now(CLOCK_MONOTONIC);

                log_info("Relabelled /dev and /run in %s.",
                         format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0));
        }
#endif

        /* Create a few default symlinks, which are normally created
         * by udevd, but some scripts might need them before we start
         * udevd. */
        dev_setup(NULL, UID_INVALID, GID_INVALID);

        /* Mark the root directory as shared in regards to mount
         * propagation. The kernel defaults to "private", but we think
         * it makes more sense to have a default of "shared" so that
         * nspawn and the container tools work out of the box. If
         * specific setups need other settings they can reset the
         * propagation mode to private if needed. */
        if (detect_container() <= 0)
                if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
                        log_warning_errno(errno, "Failed to set up the root directory for shared mount propagation: %m");

        /* Create a few directories we always want around, Note that
         * sd_booted() checks for /run/systemd/system, so this mkdir
         * really needs to stay for good, otherwise software that
         * copied sd-daemon.c into their sources will misdetect
         * systemd. */
        mkdir_label("/run/systemd", 0755);
        mkdir_label("/run/systemd/system", 0755);
        mkdir_label("/run/systemd/inaccessible", 0000);

        return 0;
}
Esempio n. 11
0
int mount_cgroup_controllers(char ***join_controllers) {
    int r;
    char buf[LINE_MAX];
    _cleanup_set_free_free_ Set *controllers = NULL;
    _cleanup_fclose_ FILE *f;

    /* Mount all available cgroup controllers that are built into the kernel. */

    f = fopen("/proc/cgroups", "re");
    if (!f) {
        log_error("Failed to enumerate cgroup controllers: %m");
        return 0;
    }

    controllers = set_new(string_hash_func, string_compare_func);
    if (!controllers)
        return log_oom();

    /* Ignore the header line */
    (void) fgets(buf, sizeof(buf), f);

    for (;;) {
        char *controller;
        int enabled = 0;

        if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {

            if (feof(f))
                break;

            log_error("Failed to parse /proc/cgroups.");
            return -EIO;
        }

        if (!enabled) {
            free(controller);
            continue;
        }

        r = set_consume(controllers, controller);
        if (r < 0) {
            log_error("Failed to add controller to set.");
            return r;
        }
    }

    for (;;) {
        MountPoint p = {
            .what = "cgroup",
            .type = "cgroup",
            .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
            .mode = MNT_IN_CONTAINER,
        };
        char ***k = NULL;
        _cleanup_free_ char *options = NULL, *controller;

        controller = set_steal_first(controllers);
        if (!controller)
            break;

        if (join_controllers)
            for (k = join_controllers; *k; k++)
                if (strv_find(*k, controller))
                    break;

        if (k && *k) {
            char **i, **j;

            for (i = *k, j = *k; *i; i++) {

                if (!streq(*i, controller)) {
                    char _cleanup_free_ *t;

                    t = set_remove(controllers, *i);
                    if (!t) {
                        free(*i);
                        continue;
                    }
                }

                *(j++) = *i;
            }

            *j = NULL;

            options = strv_join(*k, ",");
            if (!options)
                return log_oom();
        } else {
            options = controller;
            controller = NULL;
        }

        p.where = strappenda("/sys/fs/cgroup/", options);
        p.options = options;

        r = mount_one(&p, true);
        if (r < 0)
            return r;

        if (r > 0 && k && *k) {
            char **i;

            for (i = *k; *i; i++) {
                char *t = strappenda("/sys/fs/cgroup/", *i);

                r = symlink(options, t);
                if (r < 0 && errno != EEXIST) {
                    log_error("Failed to create symlink %s: %m", t);
                    return -errno;
                }
            }
        }
    }

    return 0;
}

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 (_unlikely_(ftwbuf->level == 0))
        return FTW_CONTINUE;

    label_fix(fpath, false, false);

    /* /run/initramfs is static data and big, no need to
     * dynamically relabel its contents at boot... */
    if (_unlikely_(ftwbuf->level == 1 &&
                   tflag == FTW_D &&
                   streq(fpath, "/run/initramfs")))
        return FTW_SKIP_SUBTREE;

    return FTW_CONTINUE;
};

int mount_setup(bool loaded_policy) {
    int r;
    unsigned i;

    for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
        r = mount_one(mount_table + i, true);

        if (r < 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|FTW_ACTIONRETVAL);
        nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);

        after_relabel = now(CLOCK_MONOTONIC);

        log_info("Relabelled /dev and /run in %s.",
                 format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0));
    }

    /* Create a few default symlinks, which are normally created
     * by udevd, but some scripts might need them before we start
     * udevd. */
    dev_setup(NULL);

    /* Mark the root directory as shared in regards to mount
     * propagation. The kernel defaults to "private", but we think
     * it makes more sense to have a default of "shared" so that
     * nspawn and the container tools work out of the box. If
     * specific setups need other settings they can reset the
     * propagation mode to private if needed. */
    if (detect_container(NULL) <= 0)
        if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
            log_warning("Failed to set up the root directory for shared mount propagation: %m");

    /* Create a few directories we always want around, Note that
     * sd_booted() checks for /run/systemd/system, so this mkdir
     * really needs to stay for good, otherwise software that
     * copied sd-daemon.c into their sources will misdetect
     * systemd. */
    mkdir_label("/run/systemd", 0755);
    mkdir_label("/run/systemd/system", 0755);
    mkdir_label("/run/systemd/inaccessible", 0000);

    return 0;
}
Esempio n. 12
0
/* Use this function only if you do not have direct access to /proc/self/mountinfo but the caller can open it
 * for you. This is the case when /proc is masked or not mounted. Otherwise, use bind_remount_recursive. */
int bind_remount_recursive_with_mountinfo(
                const char *prefix,
                unsigned long new_flags,
                unsigned long flags_mask,
                char **blacklist,
                FILE *proc_self_mountinfo) {

        _cleanup_set_free_free_ Set *done = NULL;
        _cleanup_free_ char *cleaned = NULL;
        int r;

        assert(proc_self_mountinfo);

        /* Recursively remount a directory (and all its submounts) read-only or read-write. If the directory is already
         * mounted, we reuse the mount and simply mark it MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
         * operation). If it isn't we first make it one. Afterwards we apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to
         * all submounts we can access, too. When mounts are stacked on the same mount point we only care for each
         * individual "top-level" mount on each point, as we cannot influence/access the underlying mounts anyway. We
         * do not have any effect on future submounts that might get propagated, they migt be writable. This includes
         * future submounts that have been triggered via autofs.
         *
         * If the "blacklist" parameter is specified it may contain a list of subtrees to exclude from the
         * remount operation. Note that we'll ignore the blacklist for the top-level path. */

        cleaned = strdup(prefix);
        if (!cleaned)
                return -ENOMEM;

        path_simplify(cleaned, false);

        done = set_new(&path_hash_ops);
        if (!done)
                return -ENOMEM;

        for (;;) {
                _cleanup_set_free_free_ Set *todo = NULL;
                bool top_autofs = false;
                char *x;
                unsigned long orig_flags;

                todo = set_new(&path_hash_ops);
                if (!todo)
                        return -ENOMEM;

                rewind(proc_self_mountinfo);

                for (;;) {
                        _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL;
                        int k;

                        k = fscanf(proc_self_mountinfo,
                                   "%*s "       /* (1) mount id */
                                   "%*s "       /* (2) parent id */
                                   "%*s "       /* (3) major:minor */
                                   "%*s "       /* (4) root */
                                   "%ms "       /* (5) mount point */
                                   "%*s"        /* (6) mount options (superblock) */
                                   "%*[^-]"     /* (7) optional fields */
                                   "- "         /* (8) separator */
                                   "%ms "       /* (9) file system type */
                                   "%*s"        /* (10) mount source */
                                   "%*s"        /* (11) mount options (bind mount) */
                                   "%*[^\n]",   /* some rubbish at the end */
                                   &path,
                                   &type);
                        if (k != 2) {
                                if (k == EOF)
                                        break;

                                continue;
                        }

                        r = cunescape(path, UNESCAPE_RELAX, &p);
                        if (r < 0)
                                return r;

                        if (!path_startswith(p, cleaned))
                                continue;

                        /* Ignore this mount if it is blacklisted, but only if it isn't the top-level mount we shall
                         * operate on. */
                        if (!path_equal(cleaned, p)) {
                                bool blacklisted = false;
                                char **i;

                                STRV_FOREACH(i, blacklist) {

                                        if (path_equal(*i, cleaned))
                                                continue;

                                        if (!path_startswith(*i, cleaned))
                                                continue;

                                        if (path_startswith(p, *i)) {
                                                blacklisted = true;
                                                log_debug("Not remounting %s blacklisted by %s, called for %s", p, *i, cleaned);
                                                break;
                                        }
                                }
                                if (blacklisted)
                                        continue;
                        }

                        /* Let's ignore autofs mounts.  If they aren't
                         * triggered yet, we want to avoid triggering
                         * them, as we don't make any guarantees for
                         * future submounts anyway.  If they are
                         * already triggered, then we will find
                         * another entry for this. */
                        if (streq(type, "autofs")) {
                                top_autofs = top_autofs || path_equal(cleaned, p);
                                continue;
                        }

                        if (!set_contains(done, p)) {
                                r = set_consume(todo, p);
                                p = NULL;
                                if (r == -EEXIST)
                                        continue;
                                if (r < 0)
                                        return r;
                        }
                }

                /* If we have no submounts to process anymore and if
                 * the root is either already done, or an autofs, we
                 * are done */
                if (set_isempty(todo) &&
                    (top_autofs || set_contains(done, cleaned)))
                        return 0;

                if (!set_contains(done, cleaned) &&
                    !set_contains(todo, cleaned)) {
                        /* The prefix directory itself is not yet a mount, make it one. */
                        if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
                                return -errno;

                        orig_flags = 0;
                        (void) get_mount_flags(cleaned, &orig_flags);
                        orig_flags &= ~MS_RDONLY;

                        if (mount(NULL, cleaned, NULL, (orig_flags & ~flags_mask)|MS_BIND|MS_REMOUNT|new_flags, NULL) < 0)
                                return -errno;

                        log_debug("Made top-level directory %s a mount point.", prefix);

                        r = set_put_strdup(done, cleaned);
                        if (r < 0)
                                return r;
                }

                while ((x = set_steal_first(todo))) {

                        r = set_consume(done, x);
                        if (IN_SET(r, 0, -EEXIST))
                                continue;
                        if (r < 0)
                                return r;

                        /* Deal with mount points that are obstructed by a later mount */
                        r = path_is_mount_point(x, NULL, 0);
                        if (IN_SET(r, 0, -ENOENT))
                                continue;
                        if (IN_SET(r, -EACCES, -EPERM)) {
                                /* Even if root user invoke this, submounts under private FUSE or NFS mount points
                                 * may not be acceessed. E.g.,
                                 *
                                 * $ bindfs --no-allow-other ~/mnt/mnt ~/mnt/mnt
                                 * $ bindfs --no-allow-other ~/mnt ~/mnt
                                 *
                                 * Then, root user cannot access the mount point ~/mnt/mnt.
                                 * In such cases, the submounts are ignored, as we have no way to manage them. */
                                log_debug_errno(r, "Failed to determine '%s' is mount point or not, ignoring: %m", x);
                                continue;
                        }
                        if (r < 0)
                                return r;

                        /* Try to reuse the original flag set */
                        orig_flags = 0;
                        (void) get_mount_flags(x, &orig_flags);
                        orig_flags &= ~MS_RDONLY;

                        if (mount(NULL, x, NULL, (orig_flags & ~flags_mask)|MS_BIND|MS_REMOUNT|new_flags, NULL) < 0)
                                return -errno;

                        log_debug("Remounted %s read-only.", x);
                }
        }
Esempio n. 13
0
/* Mount legacy cgroup hierarchy when cgroup namespaces are unsupported. */
static int mount_legacy_cgns_unsupported(
                const char *dest,
                CGroupUnified unified_requested,
                bool userns,
                uid_t uid_shift,
                uid_t uid_range,
                const char *selinux_apifs_context) {

        _cleanup_set_free_free_ Set *controllers = NULL;
        const char *cgroup_root;
        int r;

        cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");

        (void) mkdir_p(cgroup_root, 0755);

        /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
        r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
        if (r < 0)
                return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
        if (r == 0) {
                _cleanup_free_ char *options = NULL;

                r = tmpfs_patch_options("mode=755", uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &options);
                if (r < 0)
                        return log_oom();

                r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
                                  MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
                if (r < 0)
                        return r;
        }

        r = cg_all_unified();
        if (r < 0)
                return r;
        if (r > 0)
                goto skip_controllers;

        r = cg_kernel_controllers(&controllers);
        if (r < 0)
                return log_error_errno(r, "Failed to determine cgroup controllers: %m");

        for (;;) {
                _cleanup_free_ char *controller = NULL, *origin = NULL, *combined = NULL;

                controller = set_steal_first(controllers);
                if (!controller)
                        break;

                origin = prefix_root("/sys/fs/cgroup/", controller);
                if (!origin)
                        return log_oom();

                r = readlink_malloc(origin, &combined);
                if (r == -EINVAL) {
                        /* Not a symbolic link, but directly a single cgroup hierarchy */

                        r = mount_legacy_cgroup_hierarchy(dest, controller, controller, true);
                        if (r < 0)
                                return r;

                } else if (r < 0)
                        return log_error_errno(r, "Failed to read link %s: %m", origin);
                else {
                        _cleanup_free_ char *target = NULL;

                        target = prefix_root(dest, origin);
                        if (!target)
                                return log_oom();

                        /* A symbolic link, a combination of controllers in one hierarchy */

                        if (!filename_is_valid(combined)) {
                                log_warning("Ignoring invalid combined hierarchy %s.", combined);
                                continue;
                        }

                        r = mount_legacy_cgroup_hierarchy(dest, combined, combined, true);
                        if (r < 0)
                                return r;

                        r = symlink_idempotent(combined, target, false);
                        if (r == -EINVAL)
                                return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
                        if (r < 0)
                                return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
                }
        }

skip_controllers:
        if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
                r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
                if (r < 0)
                        return r;
        }

        r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
        if (r < 0)
                return r;

        return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
                             MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
}
Esempio n. 14
0
/* Mount a legacy cgroup hierarchy when cgroup namespaces are supported. */
static int mount_legacy_cgns_supported(
                const char *dest,
                CGroupUnified unified_requested,
                bool userns,
                uid_t uid_shift,
                uid_t uid_range,
                const char *selinux_apifs_context) {

        _cleanup_set_free_free_ Set *controllers = NULL;
        const char *cgroup_root = "/sys/fs/cgroup", *c;
        int r;

        (void) mkdir_p(cgroup_root, 0755);

        /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
        r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
        if (r < 0)
                return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
        if (r == 0) {
                _cleanup_free_ char *options = NULL;

                /* When cgroup namespaces are enabled and user namespaces are
                 * used then the mount of the cgroupfs is done *inside* the new
                 * user namespace. We're root in the new user namespace and the
                 * kernel will happily translate our uid/gid to the correct
                 * uid/gid as seen from e.g. /proc/1/mountinfo. So we simply
                 * pass uid 0 and not uid_shift to tmpfs_patch_options().
                 */
                r = tmpfs_patch_options("mode=755", 0, selinux_apifs_context, &options);
                if (r < 0)
                        return log_oom();

                r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
                                  MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
                if (r < 0)
                        return r;
        }

        r = cg_all_unified();
        if (r < 0)
                return r;
        if (r > 0)
                goto skip_controllers;

        r = get_process_controllers(&controllers);
        if (r < 0)
                return log_error_errno(r, "Failed to determine cgroup controllers: %m");

        for (;;) {
                _cleanup_free_ const char *controller = NULL;

                controller = set_steal_first(controllers);
                if (!controller)
                        break;

                r = mount_legacy_cgroup_hierarchy("", controller, controller, !userns);
                if (r < 0)
                        return r;

                /* When multiple hierarchies are co-mounted, make their
                 * constituting individual hierarchies a symlink to the
                 * co-mount.
                 */
                c = controller;
                for (;;) {
                        _cleanup_free_ char *target = NULL, *tok = NULL;

                        r = extract_first_word(&c, &tok, ",", 0);
                        if (r < 0)
                                return log_error_errno(r, "Failed to extract co-mounted cgroup controller: %m");
                        if (r == 0)
                                break;

                        if (streq(controller, tok))
                                break;

                        target = prefix_root("/sys/fs/cgroup/", tok);
                        if (!target)
                                return log_oom();

                        r = symlink_idempotent(controller, target, false);
                        if (r == -EINVAL)
                                return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
                        if (r < 0)
                                return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
                }
        }

skip_controllers:
        if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
                r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
                if (r < 0)
                        return r;
        }

        r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
        if (r < 0)
                return r;

        if (!userns)
                return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
                                     MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");

        return 0;
}
Esempio n. 15
0
static void test_struct(void) {
        Prioq *q;
        Set *s;
        unsigned previous = 0, i;
        int r;

        srand(0);

        q = prioq_new(test_compare);
        assert_se(q);

        s = set_new(test_hash, test_compare);
        assert_se(s);

        for (i = 0; i < SET_SIZE; i++) {
                struct test *t;

                t = new0(struct test, 1);
                assert_se(t);
                t->value = (unsigned) rand();

                r = prioq_put(q, t, &t->idx);
                assert_se(r >= 0);

                if (i % 4 == 0) {
                        r = set_consume(s, t);
                        assert_se(r >= 0);
                }
        }

        for (;;) {
                struct test *t;

                t = set_steal_first(s);
                if (!t)
                        break;

                r = prioq_remove(q, t, &t->idx);
                assert_se(r > 0);

                free(t);
        }

        for (i = 0; i < SET_SIZE * 3 / 4; i++) {
                struct test *t;

                assert_se(prioq_size(q) == (SET_SIZE * 3 / 4) - i);

                t = prioq_pop(q);
                assert_se(t);

                assert_se(previous <= t->value);
                previous = t->value;
                free(t);
        }

        assert_se(prioq_isempty(q));
        prioq_free(q);

        assert_se(set_isempty(s));
        set_free(s);
}