Beispiel #1
0
static int apply_timestamp(const char *path, struct timespec *ts) {
        struct timespec twice[2] = {
                *ts,
                *ts
        };
        struct stat st;

        assert(path);
        assert(ts);

        if (stat(path, &st) >= 0) {
                /* Is the timestamp file already newer than the OS? If
                 * so, there's nothing to do. We ignore the nanosecond
                 * component of the timestamp, since some file systems
                 * do not support any better accuracy than 1s and we
                 * have no way to identify the accuracy
                 * available. Most notably ext4 on small disks (where
                 * 128 byte inodes are used) does not support better
                 * accuracy than 1s. */
                if (st.st_mtim.tv_sec > ts->tv_sec)
                        return 0;

                /* It is older? Then let's update it */
                if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) {

                        if (errno == EROFS)
                                return log_debug("Can't update timestamp file %s, file system is read-only.", path);

                        return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
                }

        } else if (errno == ENOENT) {
                _cleanup_close_ int fd = -1;
                int r;

                /* The timestamp file doesn't exist yet? Then let's create it. */

                r = mac_selinux_create_file_prepare(path, S_IFREG);
                if (r < 0)
                        return log_error_errno(r, "Failed to set SELinux context for %s: %m", path);

                fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
                mac_selinux_create_file_clear();

                if (fd < 0) {
                        if (errno == EROFS)
                                return log_debug("Can't create timestamp file %s, file system is read-only.", path);

                        return log_error_errno(errno, "Failed to create timestamp file %s: %m", path);
                }

                (void) loop_write(fd, MESSAGE, strlen(MESSAGE), false);

                if (futimens(fd, twice) < 0)
                        return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
        } else
                log_error_errno(errno, "Failed to stat() timestamp file %s: %m", path);

        return 0;
}
static int apply_timestamp(const char *path, struct timespec *ts) {
        struct timespec twice[2];
        struct stat st;

        assert(path);
        assert(ts);

        if (stat(path, &st) >= 0) {
                /* Is the timestamp file already newer than the OS? If so, there's nothing to do. */
                if (st.st_mtim.tv_sec > ts->tv_sec ||
                    (st.st_mtim.tv_sec == ts->tv_sec && st.st_mtim.tv_nsec >= ts->tv_nsec))
                        return 0;

                /* It is older? Then let's update it */
                twice[0] = *ts;
                twice[1] = *ts;

                if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) {

                        if (errno == EROFS)
                                return log_debug("Can't update timestamp file %s, file system is read-only.", path);

                        return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
                }

        } else if (errno == ENOENT) {
                _cleanup_close_ int fd = -1;
                int r;

                /* The timestamp file doesn't exist yet? Then let's create it. */

                r = mac_selinux_create_file_prepare(path, S_IFREG);
                if (r < 0)
                        return log_error_errno(r, "Failed to set SELinux context for %s: %m", path);

                fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
                mac_selinux_create_file_clear();

                if (fd < 0) {
                        if (errno == EROFS)
                                return log_debug("Can't create timestamp file %s, file system is read-only.", path);

                        return log_error_errno(errno, "Failed to create timestamp file %s: %m", path);
                }

                (void) loop_write(fd, MESSAGE, strlen(MESSAGE), false);

                twice[0] = *ts;
                twice[1] = *ts;

                if (futimens(fd, twice) < 0)
                        return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
        } else
                log_error_errno(errno, "Failed to stat() timestamp file %s: %m", path);

        return 0;
}
Beispiel #3
0
int write_env_file_label(const char *fname, char **l) {
        int r;

        r = mac_selinux_create_file_prepare(fname, S_IFREG);
        if (r < 0)
                return r;

        r = write_env_file(fname, l);

        mac_selinux_create_file_clear();

        return r;
}
Beispiel #4
0
int write_string_file_atomic_label(const char *fn, const char *line) {
        int r;

        r = mac_selinux_create_file_prepare(fn, S_IFREG);
        if (r < 0)
                return r;

        r = write_string_file(fn, line, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);

        mac_selinux_create_file_clear();

        return r;
}
Beispiel #5
0
static int apply_timestamp(const char *path, struct timespec *ts) {
        struct timespec twice[2] = {
                *ts,
                *ts
        };
        int fd = -1;
        _cleanup_fclose_ FILE *f = NULL;
        int r;

        assert(path);
        assert(ts);

        /*
         * We store the timestamp both as mtime of the file and in the file itself,
         * to support filesystems which cannot store nanosecond-precision timestamps.
         * Hence, don't bother updating the file, let's just rewrite it.
         */

        r = mac_selinux_create_file_prepare(path, S_IFREG);
        if (r < 0)
                return log_error_errno(r, "Failed to set SELinux context for %s: %m", path);

        fd = open(path, O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
        mac_selinux_create_file_clear();

        if (fd < 0) {
                if (errno == EROFS)
                        return log_debug("Can't create timestamp file %s, file system is read-only.", path);

                return log_error_errno(errno, "Failed to create/open timestamp file %s: %m", path);
        }

        f = fdopen(fd, "w");
        if (!f) {
                safe_close(fd);
                return log_error_errno(errno, "Failed to fdopen() timestamp file %s: %m", path);
        }

        (void) fprintf(f,
                       "%s"
                       "TimestampNSec=" NSEC_FMT "\n",
                       MESSAGE, timespec_load_nsec(ts));

        fflush(f);

        if (futimens(fd, twice) < 0)
                return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);

        return 0;
}
Beispiel #6
0
int fopen_temporary_label(const char *target,
                          const char *path, FILE **f, char **temp_path) {
        int r;

        r = mac_selinux_create_file_prepare(target, S_IFREG);
        if (r < 0)
                return r;

        r = fopen_temporary(path, f, temp_path);

        mac_selinux_create_file_clear();

        return r;
}
Beispiel #7
0
int mkdir_label(const char *path, mode_t mode) {
        int r;

        assert(path);

        r = mac_selinux_create_file_prepare(path, S_IFDIR);
        if (r < 0)
                return r;

        r = mkdir_errno_wrapper(path, mode);
        mac_selinux_create_file_clear();
        if (r < 0)
                return r;

        return mac_smack_fix(path, 0);
}
Beispiel #8
0
int mkdir_label(const char *path, mode_t mode) {
        int r;

        assert(path);

        r = mac_selinux_create_file_prepare(path, S_IFDIR);
        if (r < 0)
                return r;

        if (mkdir(path, mode) < 0)
                r = -errno;

        mac_selinux_create_file_clear();

        if (r < 0)
                return r;

        return mac_smack_fix(path, false, false);
}
Beispiel #9
0
int symlink_label(const char *old_path, const char *new_path) {
        int r;

        assert(old_path);
        assert(new_path);

        r = mac_selinux_create_file_prepare(new_path, S_IFLNK);
        if (r < 0)
                return r;

        if (symlink(old_path, new_path) < 0)
                r = -errno;

        mac_selinux_create_file_clear();

        if (r < 0)
                return r;

        return mac_smack_fix(new_path, false, false);
}
Beispiel #10
0
static int mount_private_dev(MountEntry *m) {
        static const char devnodes[] =
                "/dev/null\0"
                "/dev/zero\0"
                "/dev/full\0"
                "/dev/random\0"
                "/dev/urandom\0"
                "/dev/tty\0";

        char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
        const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
        _cleanup_umask_ mode_t u;
        int r;

        assert(m);

        u = umask(0000);

        if (!mkdtemp(temporary_mount))
                return -errno;

        dev = strjoina(temporary_mount, "/dev");
        (void) mkdir(dev, 0755);
        if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
                r = -errno;
                goto fail;
        }

        devpts = strjoina(temporary_mount, "/dev/pts");
        (void) mkdir(devpts, 0755);
        if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
                r = -errno;
                goto fail;
        }

        devptmx = strjoina(temporary_mount, "/dev/ptmx");
        if (symlink("pts/ptmx", devptmx) < 0) {
                r = -errno;
                goto fail;
        }

        devshm = strjoina(temporary_mount, "/dev/shm");
        (void) mkdir(devshm, 01777);
        r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
        if (r < 0) {
                r = -errno;
                goto fail;
        }

        devmqueue = strjoina(temporary_mount, "/dev/mqueue");
        (void) mkdir(devmqueue, 0755);
        (void) mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);

        devhugepages = strjoina(temporary_mount, "/dev/hugepages");
        (void) mkdir(devhugepages, 0755);
        (void) mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);

        devlog = strjoina(temporary_mount, "/dev/log");
        (void) symlink("/run/systemd/journal/dev-log", devlog);

        NULSTR_FOREACH(d, devnodes) {
                _cleanup_free_ char *dn = NULL;
                struct stat st;

                r = stat(d, &st);
                if (r < 0) {

                        if (errno == ENOENT)
                                continue;

                        r = -errno;
                        goto fail;
                }

                if (!S_ISBLK(st.st_mode) &&
                    !S_ISCHR(st.st_mode)) {
                        r = -EINVAL;
                        goto fail;
                }

                if (st.st_rdev == 0)
                        continue;

                dn = strappend(temporary_mount, d);
                if (!dn) {
                        r = -ENOMEM;
                        goto fail;
                }

                mac_selinux_create_file_prepare(d, st.st_mode);
                r = mknod(dn, st.st_mode, st.st_rdev);
                mac_selinux_create_file_clear();

                if (r < 0) {
                        r = -errno;
                        goto fail;
                }
        }
Beispiel #11
0
static int node_symlink(struct udev_device *dev, const char *node, const char *slink) {
        struct stat stats;
        char target[UTIL_PATH_SIZE];
        char *s;
        size_t l;
        char slink_tmp[UTIL_PATH_SIZE + 32];
        int i = 0;
        int tail = 0;
        int err = 0;

        /* use relative link */
        target[0] = '\0';
        while (node[i] && (node[i] == slink[i])) {
                if (node[i] == '/')
                        tail = i+1;
                i++;
        }
        s = target;
        l = sizeof(target);
        while (slink[i] != '\0') {
                if (slink[i] == '/')
                        l = strpcpy(&s, l, "../");
                i++;
        }
        l = strscpy(s, l, &node[tail]);
        if (l == 0) {
                err = -EINVAL;
                goto exit;
        }

        /* preserve link with correct target, do not replace node of other device */
        if (lstat(slink, &stats) == 0) {
                if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
                        log_error("conflicting device node '%s' found, link to '%s' will not be created", slink, node);
                        goto exit;
                } else if (S_ISLNK(stats.st_mode)) {
                        char buf[UTIL_PATH_SIZE];
                        int len;

                        len = readlink(slink, buf, sizeof(buf));
                        if (len > 0 && len < (int)sizeof(buf)) {
                                buf[len] = '\0';
                                if (streq(target, buf)) {
                                        log_debug("preserve already existing symlink '%s' to '%s'", slink, target);
                                        label_fix(slink, true, false);
                                        utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
                                        goto exit;
                                }
                        }
                }
        } else {
                log_debug("creating symlink '%s' to '%s'", slink, target);
                do {
                        err = mkdir_parents_label(slink, 0755);
                        if (err != 0 && err != -ENOENT)
                                break;
                        mac_selinux_create_file_prepare(slink, S_IFLNK);
                        err = symlink(target, slink);
                        if (err != 0)
                                err = -errno;
                        mac_selinux_create_file_clear();
                } while (err == -ENOENT);
                if (err == 0)
                        goto exit;
        }

        log_debug("atomically replace '%s'", slink);
        strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", udev_device_get_id_filename(dev), NULL);
        unlink(slink_tmp);
        do {
                err = mkdir_parents_label(slink_tmp, 0755);
                if (err != 0 && err != -ENOENT)
                        break;
                mac_selinux_create_file_prepare(slink_tmp, S_IFLNK);
                err = symlink(target, slink_tmp);
                if (err != 0)
                        err = -errno;
                mac_selinux_create_file_clear();
        } while (err == -ENOENT);
        if (err != 0) {
                log_error_errno(errno, "symlink '%s' '%s' failed: %m", target, slink_tmp);
                goto exit;
        }
        err = rename(slink_tmp, slink);
        if (err != 0) {
                log_error_errno(errno, "rename '%s' '%s' failed: %m", slink_tmp, slink);
                unlink(slink_tmp);
        }
exit:
        return err;
}
static int node_symlink(sd_device *dev, const char *node, const char *slink) {
        _cleanup_free_ char *slink_dirname = NULL, *target = NULL;
        const char *id_filename, *slink_tmp;
        struct stat stats;
        int r;

        assert(dev);
        assert(node);
        assert(slink);

        slink_dirname = dirname_malloc(slink);
        if (!slink_dirname)
                return log_oom();

        /* use relative link */
        r = path_make_relative(slink_dirname, node, &target);
        if (r < 0)
                return log_device_error_errno(dev, r, "Failed to get relative path from '%s' to '%s': %m", slink, node);

        /* preserve link with correct target, do not replace node of other device */
        if (lstat(slink, &stats) == 0) {
                if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
                        log_device_error(dev, "Conflicting device node '%s' found, link to '%s' will not be created.", slink, node);
                        return -EOPNOTSUPP;
                } else if (S_ISLNK(stats.st_mode)) {
                        _cleanup_free_ char *buf = NULL;

                        if (readlink_malloc(slink, &buf) >= 0 &&
                            streq(target, buf)) {
                                log_device_debug(dev, "Preserve already existing symlink '%s' to '%s'", slink, target);
                                (void) label_fix(slink, LABEL_IGNORE_ENOENT);
                                (void) utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
                                return 0;
                        }
                }
        } else {
                log_device_debug(dev, "Creating symlink '%s' to '%s'", slink, target);
                do {
                        r = mkdir_parents_label(slink, 0755);
                        if (!IN_SET(r, 0, -ENOENT))
                                break;
                        mac_selinux_create_file_prepare(slink, S_IFLNK);
                        if (symlink(target, slink) < 0)
                                r = -errno;
                        mac_selinux_create_file_clear();
                } while (r == -ENOENT);
                if (r == 0)
                        return 0;
                if (r < 0)
                        log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink, target, slink);
        }

        log_device_debug(dev, "Atomically replace '%s'", slink);
        r = device_get_id_filename(dev, &id_filename);
        if (r < 0)
                return log_device_error_errno(dev, r, "Failed to get id_filename: %m");
        slink_tmp = strjoina(slink, ".tmp-", id_filename);
        (void) unlink(slink_tmp);
        do {
                r = mkdir_parents_label(slink_tmp, 0755);
                if (!IN_SET(r, 0, -ENOENT))
                        break;
                mac_selinux_create_file_prepare(slink_tmp, S_IFLNK);
                if (symlink(target, slink_tmp) < 0)
                        r = -errno;
                mac_selinux_create_file_clear();
        } while (r == -ENOENT);
        if (r < 0)
                return log_device_error_errno(dev, r, "Failed to create symlink '%s' to '%s': %m", slink_tmp, target);

        if (rename(slink_tmp, slink) < 0) {
                r = log_device_error_errno(dev, errno, "Failed to rename '%s' to '%s' failed: %m", slink_tmp, slink);
                (void) unlink(slink_tmp);
        }

        return r;
}