diff options
author | Lennart Poettering <lennart@poettering.net> | 2022-07-08 10:05:57 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2022-07-08 17:43:49 +0200 |
commit | 03bc11d1c491d6b8fed1e43c2929790d004d7367 (patch) | |
tree | 5021f0a3c79c7cfa44c174ab0dbaf947bbbd96e6 | |
parent | tmpfiles: take error code from "errno" earlier (diff) | |
download | systemd-03bc11d1c491d6b8fed1e43c2929790d004d7367.tar.xz systemd-03bc11d1c491d6b8fed1e43c2929790d004d7367.zip |
mac: rework labelling code to be simpler, and less racy
This merges the various labelling calls into a single label_fix_full(),
which can operate on paths, on inode fds, and in a dirfd/fname style
(i.e. like openat()). It also systematically separates the path to look
up in the db from the path we actually use to reference the inode to
relabel.
This then ports tmpfiles over to labelling by fd. This should make the
code a bit less racy, as we'll try hard to always operate on the very
same inode, pinning it via an fd.
User-visibly the behaviour should not change.
Diffstat (limited to '')
-rw-r--r-- | src/core/execute.c | 2 | ||||
-rw-r--r-- | src/core/namespace.c | 6 | ||||
-rw-r--r-- | src/shared/label.c | 23 | ||||
-rw-r--r-- | src/shared/label.h | 5 | ||||
-rw-r--r-- | src/shared/mkdir-label.c | 2 | ||||
-rw-r--r-- | src/shared/selinux-util.c | 106 | ||||
-rw-r--r-- | src/shared/selinux-util.h | 10 | ||||
-rw-r--r-- | src/shared/smack-util.c | 98 | ||||
-rw-r--r-- | src/shared/smack-util.h | 6 | ||||
-rw-r--r-- | src/tmpfiles/tmpfiles.c | 2 | ||||
-rw-r--r-- | src/udev/udev-node.c | 2 |
11 files changed, 137 insertions, 125 deletions
diff --git a/src/core/execute.c b/src/core/execute.c index 962edc1eee..3be219fe1c 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -3081,7 +3081,7 @@ static int setup_credentials_internal( assert(!must_mount || workspace_mounted > 0); where = workspace_mounted ? workspace : final; - (void) label_fix_container(where, final, 0); + (void) label_fix_full(AT_FDCWD, where, final, 0); r = acquire_credentials(context, params, unit, where, uid, workspace_mounted); if (r < 0) diff --git a/src/core/namespace.c b/src/core/namespace.c index 0bc10cd335..41457ea816 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -928,7 +928,7 @@ static int mount_private_dev(MountEntry *m) { if (r < 0) goto fail; - r = label_fix_container(dev, "/dev", 0); + r = label_fix_full(AT_FDCWD, dev, "/dev", 0); if (r < 0) { log_debug_errno(r, "Failed to fix label of '%s' as /dev: %m", dev); goto fail; @@ -1158,7 +1158,7 @@ static int mount_tmpfs(const MountEntry *m) { if (r < 0) return r; - r = label_fix_container(entry_path, inner_path, 0); + r = label_fix_full(AT_FDCWD, entry_path, inner_path, 0); if (r < 0) return log_debug_errno(r, "Failed to fix label of '%s' as '%s': %m", entry_path, inner_path); @@ -2758,7 +2758,7 @@ static int setup_one_tmp_dir(const char *id, const char *prefix, char **path, ch if (mkdir(y, 0777 | S_ISVTX) < 0) return -errno; - r = label_fix_container(y, prefix, 0); + r = label_fix_full(AT_FDCWD, y, prefix, 0); if (r < 0) return r; diff --git a/src/shared/label.c b/src/shared/label.c index dea15871f6..dde93e1dde 100644 --- a/src/shared/label.c +++ b/src/shared/label.c @@ -11,12 +11,29 @@ #include "selinux-util.h" #include "smack-util.h" -int label_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) { +int label_fix_full( + int atfd, + const char *inode_path, /* path of inode to apply label to */ + const char *label_path, /* path to use as database lookup key in label database (typically same as inode_path, but not always) */ + LabelFixFlags flags) { + int r, q; - r = mac_selinux_fix_container(path, inside_path, flags); - q = mac_smack_fix_container(path, inside_path, flags); + if (atfd < 0 && atfd != AT_FDCWD) + return -EBADF; + + if (!inode_path && atfd < 0) /* We need at least one of atfd and an inode path */ + return -EINVAL; + + /* If both atfd and inode_path are specified, we take the specified path relative to atfd which must be an fd to a dir. + * + * If only atfd is specified (and inode_path is NULL), we'll operated on the inode the atfd refers to. + * + * If atfd is AT_FDCWD then we'll operate on the inode the path refers to. + */ + r = mac_selinux_fix_full(atfd, inode_path, label_path, flags); + q = mac_smack_fix_full(atfd, inode_path, label_path, flags); if (r < 0) return r; if (q < 0) diff --git a/src/shared/label.h b/src/shared/label.h index ec5160284d..88aa47b7b8 100644 --- a/src/shared/label.h +++ b/src/shared/label.h @@ -10,9 +10,10 @@ typedef enum LabelFixFlags { LABEL_IGNORE_EROFS = 1 << 1, } LabelFixFlags; -int label_fix_container(const char *path, const char *inside_path, LabelFixFlags flags); +int label_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags); + static inline int label_fix(const char *path, LabelFixFlags flags) { - return label_fix_container(path, path, flags); + return label_fix_full(AT_FDCWD, path, path, flags); } int symlink_label(const char *old_path, const char *new_path); diff --git a/src/shared/mkdir-label.c b/src/shared/mkdir-label.c index 60673614c3..926d1faeeb 100644 --- a/src/shared/mkdir-label.c +++ b/src/shared/mkdir-label.c @@ -22,7 +22,7 @@ int mkdirat_label(int dirfd, const char *path, mode_t mode) { if (r < 0) return r; - return mac_smack_fix_at(dirfd, path, 0); + return mac_smack_fix_full(dirfd, path, NULL, 0); } int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c index 67ea858142..57f330f8bc 100644 --- a/src/shared/selinux-util.c +++ b/src/shared/selinux-util.c @@ -233,46 +233,19 @@ static int mac_selinux_reload(int seqno) { } #endif -int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) { - - assert(path); - assert(inside_path); - #if HAVE_SELINUX - _cleanup_close_ int fd = -1; - - /* if mac_selinux_init() wasn't called before we are a NOOP */ - if (!label_hnd) - return 0; - - /* Open the file as O_PATH, to pin it while we determine and adjust the label */ - fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); - if (fd < 0) { - if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) - return 0; - - return -errno; - } - - return mac_selinux_fix_container_fd(fd, path, inside_path, flags); -#endif - - return 0; -} - -int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_path, LabelFixFlags flags) { - - assert(fd >= 0); - assert(inside_path); +static int selinux_fix_fd( + int fd, + const char *label_path, + LabelFixFlags flags) { -#if HAVE_SELINUX _cleanup_freecon_ char* fcon = NULL; struct stat st; int r; - /* if mac_selinux_init() wasn't called before we are a NOOP */ - if (!label_hnd) - return 0; + assert(fd >= 0); + assert(label_path); + assert(path_is_absolute(label_path)); if (fstat(fd, &st) < 0) return -errno; @@ -282,42 +255,85 @@ int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_pa if (!label_hnd) return 0; - if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) < 0) { + if (selabel_lookup_raw(label_hnd, &fcon, label_path, st.st_mode) < 0) { /* If there's no label to set, then exit without warning */ if (errno == ENOENT) return 0; - r = -errno; - goto fail; + return log_enforcing_errno(errno, "Unable to lookup intended SELinux security context of %s: %m", label_path); } if (setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon) < 0) { _cleanup_freecon_ char *oldcon = NULL; + r = -errno; + /* If the FS doesn't support labels, then exit without warning */ - if (ERRNO_IS_NOT_SUPPORTED(errno)) + if (ERRNO_IS_NOT_SUPPORTED(r)) return 0; /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */ - if (errno == EROFS && (flags & LABEL_IGNORE_EROFS)) + if (r == -EROFS && (flags & LABEL_IGNORE_EROFS)) return 0; - r = -errno; - /* If the old label is identical to the new one, suppress any kind of error */ if (getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq(fcon, oldcon)) return 0; - goto fail; + return log_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", label_path); } return 0; - -fail: - return log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", strna(path), strna(inside_path)); +} #endif +int mac_selinux_fix_full( + int atfd, + const char *inode_path, + const char *label_path, + LabelFixFlags flags) { + + assert(atfd >= 0 || atfd == AT_FDCWD); + assert(atfd >= 0 || inode_path); + +#if HAVE_SELINUX + _cleanup_close_ int opened_fd = -1; + _cleanup_free_ char *p = NULL; + int inode_fd, r; + + /* if mac_selinux_init() wasn't called before we are a NOOP */ + if (!label_hnd) + return 0; + + if (inode_path) { + opened_fd = openat(atfd, inode_path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (opened_fd < 0) { + if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) + return 0; + + return -errno; + } + + inode_fd = opened_fd; + } else + inode_fd = atfd; + + if (!label_path) { + if (path_is_absolute(inode_path)) + label_path = inode_path; + else { + r = fd_get_path(inode_fd, &p); + if (r < 0) + return r; + + label_path = p; + } + } + + return selinux_fix_fd(inode_fd, label_path, flags); +#else return 0; +#endif } int mac_selinux_apply(const char *path, const char *label) { diff --git a/src/shared/selinux-util.h b/src/shared/selinux-util.h index a9ddbfc653..e9771a28fe 100644 --- a/src/shared/selinux-util.h +++ b/src/shared/selinux-util.h @@ -24,15 +24,7 @@ int mac_selinux_init(void); void mac_selinux_maybe_reload(void); void mac_selinux_finish(void); -int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags); -static inline int mac_selinux_fix(const char *path, LabelFixFlags flags) { - return mac_selinux_fix_container(path, path, flags); -} - -int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_path, LabelFixFlags flags); -static inline int mac_selinux_fix_fd(int fd, const char *path, LabelFixFlags flags) { - return mac_selinux_fix_container_fd(fd, path, path, flags); -} +int mac_selinux_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags); int mac_selinux_apply(const char *path, const char *label); int mac_selinux_apply_fd(int fd, const char *path, const char *label); diff --git a/src/shared/smack-util.c b/src/shared/smack-util.c index 8f90a2096d..f0a0f5f315 100644 --- a/src/shared/smack-util.c +++ b/src/shared/smack-util.c @@ -122,17 +122,22 @@ int mac_smack_apply_pid(pid_t pid, const char *label) { return r; } -static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) { +static int smack_fix_fd( + int fd, + const char *label_path, + LabelFixFlags flags) { + const char *label; struct stat st; int r; /* The caller should have done the sanity checks. */ - assert(abspath); - assert(path_is_absolute(abspath)); + assert(fd >= 0); + assert(label_path); + assert(path_is_absolute(label_path)); /* Path must be in /dev. */ - if (!path_startswith(abspath, "/dev")) + if (!path_startswith(label_path, "/dev")) return 0; if (fstat(fd, &st) < 0) @@ -171,70 +176,53 @@ static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) { streq(old_label, label)) return 0; - return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", abspath); + return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", label_path); } return 0; } -int mac_smack_fix_at(int dir_fd, 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; - - if (dir_fd < 0) { - if (dir_fd != AT_FDCWD) - return -EBADF; - - return mac_smack_fix(path, flags); - } - - fd = openat(dir_fd, path, O_NOFOLLOW|O_CLOEXEC|O_PATH); - if (fd < 0) { - if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) - return 0; +int mac_smack_fix_full( + int atfd, + const char *inode_path, + const char *label_path, + LabelFixFlags flags) { - return -errno; - } - - if (!path_is_absolute(path)) { - r = fd_get_path(fd, &p); - if (r < 0) - return r; - path = p; - } - - return smack_fix_fd(fd, path, flags); -} + _cleanup_close_ int opened_fd = -1; + _cleanup_free_ char *p = NULL; + int r, inode_fd; -int mac_smack_fix_container(const char *path, const char *inside_path, LabelFixFlags flags) { - _cleanup_free_ char *abspath = NULL; - _cleanup_close_ int fd = -1; - int r; - - assert(path); + assert(atfd >= 0 || atfd == AT_FDCWD); + assert(atfd >= 0 || inode_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; + if (inode_path) { + opened_fd = openat(atfd, inode_path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (opened_fd < 0) { + if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) + return 0; + + return -errno; + } + inode_fd = opened_fd; + } else + inode_fd = atfd; + + if (!label_path) { + if (path_is_absolute(inode_path)) + label_path = inode_path; + else { + r = fd_get_path(inode_fd, &p); + if (r < 0) + return r; + + label_path = p; + } } - return smack_fix_fd(fd, inside_path, flags); + return smack_fix_fd(inode_fd, label_path, flags); } int mac_smack_copy(const char *dest, const char *src) { diff --git a/src/shared/smack-util.h b/src/shared/smack-util.h index df91c89e01..da8be5e6f0 100644 --- a/src/shared/smack-util.h +++ b/src/shared/smack-util.h @@ -29,13 +29,11 @@ typedef enum SmackAttr { bool mac_smack_use(void); -int mac_smack_fix_container(const char *path, const char *inside_path, LabelFixFlags flags); +int mac_smack_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags); static inline int mac_smack_fix(const char *path, LabelFixFlags flags) { - return mac_smack_fix_container(path, path, flags); + return mac_smack_fix_full(AT_FDCWD, path, path, 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_; int mac_smack_read(const char *path, SmackAttr attr, char **label); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 6406a64237..0e389d3a31 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -923,7 +923,7 @@ static int fd_set_perms(Item *i, int fd, const char *path, const struct stat *st } shortcut: - return label_fix(path, 0); + return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, 0); } static int path_open_parent_safe(const char *path) { diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index c9f58e8c29..bb34977d97 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -677,7 +677,7 @@ static int udev_node_apply_permissions_impl( /* set the defaults */ if (!selinux) - (void) mac_selinux_fix_fd(node_fd, devnode, LABEL_IGNORE_ENOENT); + (void) mac_selinux_fix_full(node_fd, NULL, devnode, LABEL_IGNORE_ENOENT); if (!smack) (void) mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, NULL); } |