diff options
author | Lennart Poettering <lennart@poettering.net> | 2018-08-03 18:11:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-03 18:11:36 +0200 |
commit | 685499007fc536f5e78ebb49cb67561e186f665e (patch) | |
tree | fe4c039d8042ec21f1d312e5b7f1c689b5ef21e0 /src/basic | |
parent | Merge pull request #9791 from poettering/user-runtime-dir-fixes (diff) | |
parent | path-util: make use of path_join() in path_make_absolute_cwd() (diff) | |
download | systemd-685499007fc536f5e78ebb49cb67561e186f665e.tar.xz systemd-685499007fc536f5e78ebb49cb67561e186f665e.zip |
Merge pull request #8822 from fbuihuu/rfc-tmpfiles-safe-upstream
Make tmpfiles safe
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/btrfs-util.c | 26 | ||||
-rw-r--r-- | src/basic/btrfs-util.h | 1 | ||||
-rw-r--r-- | src/basic/fileio.c | 8 | ||||
-rw-r--r-- | src/basic/fs-util.c | 29 | ||||
-rw-r--r-- | src/basic/fs-util.h | 2 | ||||
-rw-r--r-- | src/basic/label.h | 1 | ||||
-rw-r--r-- | src/basic/mkdir-label.c | 17 | ||||
-rw-r--r-- | src/basic/mkdir.c | 6 | ||||
-rw-r--r-- | src/basic/mkdir.h | 1 | ||||
-rw-r--r-- | src/basic/path-util.c | 5 | ||||
-rw-r--r-- | src/basic/selinux-util.c | 83 | ||||
-rw-r--r-- | src/basic/selinux-util.h | 1 | ||||
-rw-r--r-- | src/basic/smack-util.c | 91 | ||||
-rw-r--r-- | src/basic/smack-util.h | 1 | ||||
-rw-r--r-- | src/basic/stat-util.c | 11 | ||||
-rw-r--r-- | src/basic/stat-util.h | 1 |
16 files changed, 217 insertions, 67 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index efac0b9420..abd34824e7 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -116,8 +116,25 @@ int btrfs_is_subvol(const char *path) { return btrfs_is_subvol_fd(fd); } -int btrfs_subvol_make(const char *path) { +int btrfs_subvol_make_fd(int fd, const char *subvolume) { struct btrfs_ioctl_vol_args args = {}; + int r; + + assert(subvolume); + + r = validate_subvolume_name(subvolume); + if (r < 0) + return r; + + strncpy(args.name, subvolume, sizeof(args.name)-1); + + if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0) + return -errno; + + return 0; +} + +int btrfs_subvol_make(const char *path) { _cleanup_close_ int fd = -1; const char *subvolume; int r; @@ -132,12 +149,7 @@ int btrfs_subvol_make(const char *path) { if (fd < 0) return fd; - strncpy(args.name, subvolume, sizeof(args.name)-1); - - if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0) - return -errno; - - return 0; + return btrfs_subvol_make_fd(fd, subvolume); } int btrfs_subvol_set_read_only_fd(int fd, bool b) { diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index a594387b5a..b0cf6739f7 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -65,6 +65,7 @@ int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only); int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only); int btrfs_subvol_make(const char *path); +int btrfs_subvol_make_fd(int fd, const char *subvolume); int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags); int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 20d3f567c9..ea607f8cfb 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1319,8 +1319,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) { r = tmp_dir(&p); if (r < 0) return r; - } else if (isempty(p)) - return -EINVAL; + } extra = strempty(extra); @@ -1328,7 +1327,10 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) { if (!t) return -ENOMEM; - x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); + if (isempty(p)) + x = stpcpy(stpcpy(t, ".#"), extra); + else + x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); u = random_u64(); for (i = 0; i < 16; i++) { diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index aca9921de7..09fcc32e0e 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -435,6 +435,31 @@ int mkfifo_atomic(const char *path, mode_t mode) { return 0; } +int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) { + _cleanup_free_ char *t = NULL; + int r; + + assert(path); + + if (path_is_absolute(path)) + return mkfifo_atomic(path, mode); + + /* We're only interested in the (random) filename. */ + r = tempfn_random_child("", NULL, &t); + if (r < 0) + return r; + + if (mkfifoat(dirfd, t, mode) < 0) + return -errno; + + if (renameat(dirfd, t, dirfd, path) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + int get_files_in_directory(const char *path, char ***list) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; @@ -670,7 +695,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN|CHASE_STEP)) == CHASE_OPEN) { /* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set * and doesn't care about any of the other special features we provide either. */ - r = open(path, O_PATH|O_CLOEXEC); + r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0)); if (r < 0) return -errno; @@ -825,7 +850,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0) return -EREMOTE; - if (S_ISLNK(st.st_mode)) { + if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) { char *joined; _cleanup_free_ char *destination = NULL; diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 754163defd..4b65625861 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -42,6 +42,7 @@ int symlink_idempotent(const char *from, const char *to); int symlink_atomic(const char *from, const char *to); int mknod_atomic(const char *path, mode_t mode, dev_t dev); int mkfifo_atomic(const char *path, mode_t mode); +int mkfifoat_atomic(int dir_fd, const char *path, mode_t mode); int get_files_in_directory(const char *path, char ***list); @@ -72,6 +73,7 @@ enum { CHASE_OPEN = 1 << 4, /* If set, return an O_PATH object to the final component */ CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */ CHASE_STEP = 1 << 6, /* If set, just execute a single step of the normalization */ + CHASE_NOFOLLOW = 1 << 7, /* Only valid with CHASE_OPEN: when the path's right-most component refers to symlink return O_PATH fd of the symlink, rather than following it. */ }; /* How many iterations to execute before returning -ELOOP */ diff --git a/src/basic/label.h b/src/basic/label.h index 08fd109bcf..594fd65974 100644 --- a/src/basic/label.h +++ b/src/basic/label.h @@ -12,6 +12,7 @@ typedef enum LabelFixFlags { int label_fix(const char *path, LabelFixFlags flags); int mkdir_label(const char *path, mode_t mode); +int mkdirat_label(int dirfd, const char *path, mode_t mode); int symlink_label(const char *old_path, const char *new_path); int btrfs_subvol_make_label(const char *path); diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c index 1d51e92e9a..0eba7fc514 100644 --- a/src/basic/mkdir-label.c +++ b/src/basic/mkdir-label.c @@ -28,6 +28,23 @@ int mkdir_label(const char *path, mode_t mode) { return mac_smack_fix(path, 0); } +int mkdirat_label(int dirfd, const char *path, mode_t mode) { + int r; + + assert(path); + + r = mac_selinux_create_file_prepare_at(dirfd, path, S_IFDIR); + if (r < 0) + return r; + + r = mkdirat_errno_wrapper(dirfd, path, mode); + mac_selinux_create_file_clear(); + if (r < 0) + return r; + + return mac_smack_fix_at(dirfd, path, 0); +} + int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { return mkdir_safe_internal(path, mode, uid, gid, flags, mkdir_label); } diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 6ab1b4422b..4bb65d5838 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -80,6 +80,12 @@ int mkdir_errno_wrapper(const char *pathname, mode_t mode) { return 0; } +int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode) { + if (mkdirat(dirfd, pathname, mode) < 0) + return -errno; + return 0; +} + int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { return mkdir_safe_internal(path, mode, uid, gid, flags, mkdir_errno_wrapper); } diff --git a/src/basic/mkdir.h b/src/basic/mkdir.h index bdca15460e..eb54853ea7 100644 --- a/src/basic/mkdir.h +++ b/src/basic/mkdir.h @@ -9,6 +9,7 @@ typedef enum MkdirFlags { } MkdirFlags; int mkdir_errno_wrapper(const char *pathname, mode_t mode); +int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode); int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags); int mkdir_parents(const char *path, mode_t mode); int mkdir_p(const char *path, mode_t mode); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index d214c72916..b62786f27e 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -110,10 +110,7 @@ int path_make_absolute_cwd(const char *p, char **ret) { if (r < 0) return r; - if (endswith(cwd, "/")) - c = strjoin(cwd, p); - else - c = strjoin(cwd, "/", p); + c = path_join(NULL, cwd, p); } if (!c) return -ENOMEM; diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index e15bd7e1fa..238b1d95e2 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -316,48 +316,89 @@ char* mac_selinux_free(char *label) { return NULL; } -int mac_selinux_create_file_prepare(const char *path, mode_t mode) { - #if HAVE_SELINUX +static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) { _cleanup_freecon_ char *filecon = NULL; + _cleanup_free_ char *path = NULL; int r; - assert(path); - - if (!label_hnd) - return 0; - - if (path_is_absolute(path)) - r = selabel_lookup_raw(label_hnd, &filecon, path, mode); - else { - _cleanup_free_ char *newpath = NULL; - - r = path_make_absolute_cwd(path, &newpath); - if (r < 0) - return r; - - r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode); - } + assert(abspath); + assert(path_is_absolute(abspath)); + r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode); if (r < 0) { /* No context specified by the policy? Proceed without setting it. */ if (errno == ENOENT) return 0; - log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path); + log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath); } else { if (setfscreatecon_raw(filecon) >= 0) return 0; /* Success! */ - log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, path); + log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath); } if (security_getenforce() > 0) return -errno; -#endif return 0; } +#endif + +int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) { + int r = 0; + +#if HAVE_SELINUX + _cleanup_free_ char *abspath = NULL; + _cleanup_close_ int fd = -1; + + assert(path); + + if (!label_hnd) + return 0; + + if (!path_is_absolute(path)) { + _cleanup_free_ char *p = NULL; + + if (dirfd == AT_FDCWD) + r = safe_getcwd(&p); + else + r = fd_get_path(dirfd, &p); + if (r < 0) + return r; + + abspath = path_join(NULL, p, path); + if (!abspath) + return -ENOMEM; + + path = abspath; + } + + r = selinux_create_file_prepare_abspath(path, mode); +#endif + return r; +} + +int mac_selinux_create_file_prepare(const char *path, mode_t mode) { + int r = 0; + +#if HAVE_SELINUX + _cleanup_free_ char *abspath = NULL; + + assert(path); + + if (!label_hnd) + return 0; + + r = path_make_absolute_cwd(path, &abspath); + if (r < 0) + return r; + + r = selinux_create_file_prepare_abspath(abspath, mode); +#endif + return r; +} void mac_selinux_create_file_clear(void) { diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 08314057fb..bd5207c318 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -23,6 +23,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * char* mac_selinux_free(char *label); int mac_selinux_create_file_prepare(const char *path, mode_t mode); +int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode); void mac_selinux_create_file_clear(void); int mac_selinux_create_socket_prepare(const char *label); diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index 9d31b7717f..5d7be1f1d5 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -122,43 +122,20 @@ int mac_smack_apply_pid(pid_t pid, const char *label) { return r; } -int mac_smack_fix(const char *path, LabelFixFlags flags) { +static int smack_fix_fd(int fd , const char *abspath, LabelFixFlags flags) { char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; - _cleanup_close_ int fd = -1; const char *label; struct stat st; int r; - assert(path); + /* The caller should have done the sanity checks. */ + assert(abspath); + assert(path_is_absolute(abspath)); - if (!mac_smack_use()) + /* Path must be in /dev. */ + if (!path_startswith(abspath, "/dev")) return 0; - /* Path must be in /dev. Note that this check is pretty sloppy, as we might be called with non-normalized paths - * and hence not detect all cases of /dev. */ - - if (path_is_absolute(path)) { - if (!path_startswith(path, "/dev")) - return 0; - } else { - _cleanup_free_ char *cwd = NULL; - - r = safe_getcwd(&cwd); - if (r < 0) - return r; - - if (!path_startswith(cwd, "/dev")) - return 0; - } - - fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); - if (fd < 0) { - if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) - return 0; - - return -errno; - } - if (fstat(fd, &st) < 0) return -errno; @@ -196,12 +173,62 @@ int mac_smack_fix(const char *path, LabelFixFlags flags) { streq(old_label, label)) return 0; - return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", path); + return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", abspath); } return 0; } +int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags) { + _cleanup_free_ char *p = NULL; + _cleanup_close_ int fd = -1; + int r; + + assert(path); + + if (!mac_smack_use()) + return 0; + + fd = openat(dirfd, path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (fd < 0) { + if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) + return 0; + + return -errno; + } + + r = fd_get_path(fd, &p); + if (r < 0) + return r; + + return smack_fix_fd(fd, p, flags); +} + +int mac_smack_fix(const char *path, LabelFixFlags flags) { + _cleanup_free_ char *abspath = NULL; + _cleanup_close_ int fd = -1; + int r; + + assert(path); + + if (!mac_smack_use()) + return 0; + + r = path_make_absolute_cwd(path, &abspath); + if (r < 0) + return r; + + fd = open(abspath, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (fd < 0) { + if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) + return 0; + + return -errno; + } + + return smack_fix_fd(fd, abspath, flags); +} + int mac_smack_copy(const char *dest, const char *src) { int r = 0; _cleanup_free_ char *label = NULL; @@ -249,6 +276,10 @@ int mac_smack_fix(const char *path, LabelFixFlags flags) { return 0; } +int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags) { + return 0; +} + int mac_smack_copy(const char *dest, const char *src) { return 0; } diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h index fd59787ecb..395ec07b57 100644 --- a/src/basic/smack-util.h +++ b/src/basic/smack-util.h @@ -30,6 +30,7 @@ typedef enum SmackAttr { bool mac_smack_use(void); int mac_smack_fix(const char *path, LabelFixFlags flags); +int mac_smack_fix_at(int dirfd, const char *path, LabelFixFlags flags); const char* smack_attr_to_string(SmackAttr i) _const_; SmackAttr smack_attr_from_string(const char *s) _pure_; diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 07154e25bb..762777e94f 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -45,6 +45,17 @@ int is_dir(const char* path, bool follow) { return !!S_ISDIR(st.st_mode); } +int is_dir_fd(int fd) { + struct stat st; + int r; + + r = fstat(fd, &st); + if (r < 0) + return -errno; + + return !!S_ISDIR(st.st_mode); +} + int is_device_node(const char *path) { struct stat info; diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index f8014ed30b..1a725f1da0 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -12,6 +12,7 @@ int is_symlink(const char *path); int is_dir(const char *path, bool follow); +int is_dir_fd(int fd); int is_device_node(const char *path); int dir_is_empty(const char *path); |