diff options
-rw-r--r-- | src/basic/label.c | 10 | ||||
-rw-r--r-- | src/basic/label.h | 7 | ||||
-rw-r--r-- | src/basic/mkdir-label.c | 2 | ||||
-rw-r--r-- | src/basic/selinux-util.c | 66 | ||||
-rw-r--r-- | src/basic/selinux-util.h | 3 | ||||
-rw-r--r-- | src/basic/smack-util.c | 75 | ||||
-rw-r--r-- | src/basic/smack-util.h | 15 | ||||
-rw-r--r-- | src/core/automount.c | 2 | ||||
-rw-r--r-- | src/core/mount-setup.c | 8 | ||||
-rw-r--r-- | src/hwdb/hwdb.c | 2 | ||||
-rw-r--r-- | src/login/logind-user.c | 2 | ||||
-rw-r--r-- | src/tmpfiles/tmpfiles.c | 2 | ||||
-rw-r--r-- | src/udev/udev-node.c | 4 | ||||
-rw-r--r-- | src/udev/udevadm-hwdb.c | 2 |
14 files changed, 123 insertions, 77 deletions
diff --git a/src/basic/label.c b/src/basic/label.c index 18c9a23fea..134dd8d80a 100644 --- a/src/basic/label.c +++ b/src/basic/label.c @@ -28,11 +28,11 @@ #include "selinux-util.h" #include "smack-util.h" -int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { +int label_fix(const char *path, LabelFixFlags flags) { int r, q; - r = mac_selinux_fix(path, ignore_enoent, ignore_erofs); - q = mac_smack_fix(path, ignore_enoent, ignore_erofs); + r = mac_selinux_fix(path, flags); + q = mac_smack_fix(path, flags); if (r < 0) return r; @@ -60,7 +60,7 @@ int symlink_label(const char *old_path, const char *new_path) { if (r < 0) return r; - return mac_smack_fix(new_path, false, false); + return mac_smack_fix(new_path, 0); } int btrfs_subvol_make_label(const char *path) { @@ -78,5 +78,5 @@ int btrfs_subvol_make_label(const char *path) { if (r < 0) return r; - return mac_smack_fix(path, false, false); + return mac_smack_fix(path, 0); } diff --git a/src/basic/label.h b/src/basic/label.h index d73dacec4f..269591c979 100644 --- a/src/basic/label.h +++ b/src/basic/label.h @@ -23,7 +23,12 @@ #include <stdbool.h> #include <sys/types.h> -int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs); +typedef enum LabelFixFlags { + LABEL_IGNORE_ENOENT = 1U << 0, + LABEL_IGNORE_EROFS = 1U << 1, +} LabelFixFlags; + +int label_fix(const char *path, LabelFixFlags flags); int mkdir_label(const char *path, mode_t mode); int symlink_label(const char *old_path, const char *new_path); diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c index 2a44d276cb..9d4ef60e77 100644 --- a/src/basic/mkdir-label.c +++ b/src/basic/mkdir-label.c @@ -44,7 +44,7 @@ int mkdir_label(const char *path, mode_t mode) { if (r < 0) return r; - return mac_smack_fix(path, false, false); + return mac_smack_fix(path, 0); } int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 0c6e99b1d7..c60057f4f7 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -34,10 +34,12 @@ #endif #include "alloc-util.h" +#include "fd-util.h" #include "log.h" #include "macro.h" #include "path-util.h" #include "selinux-util.h" +#include "stdio-util.h" #include "time-util.h" #include "util.h" @@ -51,7 +53,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free); static int cached_use = -1; static struct selabel_handle *label_hnd = NULL; -#define log_enforcing(...) log_full_errno(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, errno, __VA_ARGS__) +#define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__) +#define log_enforcing_errno(r, ...) log_full_errno(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, r, __VA_ARGS__) #endif bool mac_selinux_use(void) { @@ -120,9 +123,12 @@ void mac_selinux_finish(void) { #endif } -int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { +int mac_selinux_fix(const char *path, LabelFixFlags flags) { #if HAVE_SELINUX + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_freecon_ char* fcon = NULL; + _cleanup_close_ int fd = -1; struct stat st; int r; @@ -132,37 +138,55 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { if (!label_hnd) return 0; - r = lstat(path, &st); - if (r >= 0) { - _cleanup_freecon_ char* fcon = NULL; + /* 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; - r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); + return -errno; + } + + if (fstat(fd, &st) < 0) + return -errno; + + if (selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode) < 0) { + r = -errno; /* If there's no label to set, then exit without warning */ - if (r < 0 && errno == ENOENT) + if (r == -ENOENT) return 0; - if (r >= 0) { - r = lsetfilecon_raw(path, fcon); - - /* If the FS doesn't support labels, then exit without warning */ - if (r < 0 && errno == EOPNOTSUPP) - return 0; - } + goto fail; } - if (r < 0) { - /* Ignore ENOENT in some cases */ - if (ignore_enoent && errno == ENOENT) + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + if (setfilecon_raw(procfs_path, fcon) < 0) { + _cleanup_freecon_ char *oldcon = NULL; + + r = -errno; + + /* If the FS doesn't support labels, then exit without warning */ + if (r == -EOPNOTSUPP) return 0; - if (ignore_erofs && errno == EROFS) + /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */ + if (r == -EROFS && (flags & LABEL_IGNORE_EROFS)) return 0; - log_enforcing("Unable to fix SELinux security context of %s: %m", path); - if (security_getenforce() == 1) - return -errno; + /* If the old label is identical to the new one, suppress any kind of error */ + if (getfilecon_raw(procfs_path, &oldcon) >= 0 && streq(fcon, oldcon)) + return 0; + + goto fail; } + + return 0; + +fail: + log_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", path); + if (security_getenforce() == 1) + return r; #endif return 0; diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 9780dca81e..1cb4ea4fe0 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -25,6 +25,7 @@ #include <sys/types.h> #include "macro.h" +#include "label.h" bool mac_selinux_use(void); void mac_selinux_retest(void); @@ -32,7 +33,7 @@ void mac_selinux_retest(void); int mac_selinux_init(void); void mac_selinux_finish(void); -int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs); +int mac_selinux_fix(const char *path, LabelFixFlags flags); int mac_selinux_apply(const char *path, const char *label); int mac_selinux_get_create_label_from_exe(const char *exe, char **label); diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index f0018f013f..977de014f7 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -21,18 +21,21 @@ ***/ #include <errno.h> +#include <fcntl.h> #include <string.h> #include <sys/stat.h> #include <sys/xattr.h> #include <unistd.h> #include "alloc-util.h" +#include "fd-util.h" #include "fileio.h" #include "log.h" #include "macro.h" #include "path-util.h" #include "process-util.h" #include "smack-util.h" +#include "stdio-util.h" #include "string-table.h" #include "xattr-util.h" @@ -134,7 +137,10 @@ int mac_smack_apply_pid(pid_t pid, const char *label) { return r; } -int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { +int mac_smack_fix(const char *path, 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; @@ -143,50 +149,59 @@ int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { if (!mac_smack_use()) return 0; - /* - * Path must be in /dev and must exist - */ + /* Path must be in /dev */ if (!path_startswith(path, "/dev")) return 0; - r = lstat(path, &st); - if (r >= 0) { - const char *label; - - /* - * Label directories and character devices "*". - * Label symlinks "_". - * Don't change anything else. - */ - - if (S_ISDIR(st.st_mode)) - label = SMACK_STAR_LABEL; - else if (S_ISLNK(st.st_mode)) - label = SMACK_FLOOR_LABEL; - else if (S_ISCHR(st.st_mode)) - label = SMACK_STAR_LABEL; - else + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (fd < 0) { + if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) return 0; - r = lsetxattr(path, "security.SMACK64", label, strlen(label), 0); + return -errno; + } + + if (fstat(fd, &st) < 0) + return -errno; + + /* + * Label directories and character devices "*". + * Label symlinks "_". + * Don't change anything else. + */ + + if (S_ISDIR(st.st_mode)) + label = SMACK_STAR_LABEL; + else if (S_ISLNK(st.st_mode)) + label = SMACK_FLOOR_LABEL; + else if (S_ISCHR(st.st_mode)) + label = SMACK_STAR_LABEL; + else + return 0; + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + if (setxattr(procfs_path, "security.SMACK64", label, strlen(label), 0) < 0) { + _cleanup_free_ char *old_label = NULL; + + r = -errno; /* If the FS doesn't support labels, then exit without warning */ - if (r < 0 && errno == EOPNOTSUPP) + if (r == -EOPNOTSUPP) return 0; - } - if (r < 0) { - /* Ignore ENOENT in some cases */ - if (ignore_enoent && errno == ENOENT) + /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */ + if (r == -EROFS && (flags & LABEL_IGNORE_EROFS)) return 0; - if (ignore_erofs && errno == EROFS) + /* If the old label is identical to the new one, suppress any kind of error */ + if (getxattr_malloc(procfs_path, "security.SMACK64", &old_label, false) >= 0 && + streq(old_label, label)) return 0; - r = log_debug_errno(errno, "Unable to fix SMACK label of %s: %m", path); + return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", path); } - return r; + return 0; } int mac_smack_copy(const char *dest, const char *src) { diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h index e4d46d7736..58e6a548b6 100644 --- a/src/basic/smack-util.h +++ b/src/basic/smack-util.h @@ -25,25 +25,26 @@ #include <stdbool.h> #include <sys/types.h> +#include "label.h" #include "macro.h" #define SMACK_FLOOR_LABEL "_" #define SMACK_STAR_LABEL "*" typedef enum SmackAttr { - SMACK_ATTR_ACCESS = 0, - SMACK_ATTR_EXEC = 1, - SMACK_ATTR_MMAP = 2, - SMACK_ATTR_TRANSMUTE = 3, - SMACK_ATTR_IPIN = 4, - SMACK_ATTR_IPOUT = 5, + SMACK_ATTR_ACCESS, + SMACK_ATTR_EXEC, + SMACK_ATTR_MMAP, + SMACK_ATTR_TRANSMUTE, + SMACK_ATTR_IPIN, + SMACK_ATTR_IPOUT, _SMACK_ATTR_MAX, _SMACK_ATTR_INVALID = -1, } SmackAttr; bool mac_smack_use(void); -int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs); +int mac_smack_fix(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/core/automount.c b/src/core/automount.c index a8d773686b..bcc6b0b04e 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -346,7 +346,7 @@ static int open_dev_autofs(Manager *m) { if (m->dev_autofs_fd >= 0) return m->dev_autofs_fd; - label_fix("/dev/autofs", false, false); + (void) label_fix("/dev/autofs", 0); m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY); if (m->dev_autofs_fd < 0) diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index b7d654619c..0fe794d2af 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -168,7 +168,7 @@ static int mount_one(const MountPoint *p, bool relabel) { /* Relabel first, just in case */ if (relabel) - (void) label_fix(p->where, true, true); + (void) label_fix(p->where, LABEL_IGNORE_ENOENT|LABEL_IGNORE_EROFS); r = path_is_mount_point(p->where, NULL, AT_SYMLINK_FOLLOW); if (r < 0 && r != -ENOENT) { @@ -206,7 +206,7 @@ static int mount_one(const MountPoint *p, bool relabel) { /* Relabel again, since we now mounted something fresh here */ if (relabel) - (void) label_fix(p->where, false, false); + (void) label_fix(p->where, 0); if (p->mode & MNT_CHECK_WRITABLE) { if (access(p->where, W_OK) < 0) { @@ -374,7 +374,7 @@ static int nftw_cb( if (_unlikely_(ftwbuf->level == 0)) return FTW_CONTINUE; - label_fix(fpath, false, false); + (void) label_fix(fpath, 0); /* /run/initramfs is static data and big, no need to * dynamically relabel its contents at boot... */ @@ -413,7 +413,7 @@ int mount_setup(bool loaded_policy) { r = cg_all_unified(); if (r == 0) { (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL); - label_fix("/sys/fs/cgroup", false, false); + (void) label_fix("/sys/fs/cgroup", 0); nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL); } else if (r < 0) diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index f579ef737e..a60809ca65 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -688,7 +688,7 @@ static int hwdb_update(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failure writing database %s: %m", hwdb_bin); - return label_fix(hwdb_bin, false, false); + return label_fix(hwdb_bin, 0); } static void help(void) { diff --git a/src/login/logind-user.c b/src/login/logind-user.c index dc8feacbf9..28574f49a2 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -368,7 +368,7 @@ static int user_mkdir_runtime_path(User *u) { } } - r = label_fix(u->runtime_path, false, false); + r = label_fix(u->runtime_path, 0); if (r < 0) log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", u->runtime_path); } diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index b56b7ac963..61e76570b1 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -850,7 +850,7 @@ static int fd_set_perms(Item *i, int fd, const struct stat *st) { } shortcut: - return label_fix(path, false, false); + return label_fix(path, 0); } static int path_set_perms(Item *i, const char *path) { diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 6a3ee93ca2..755bf665ab 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -79,7 +79,7 @@ static int node_symlink(struct udev_device *dev, const char *node, const char *s buf[len] = '\0'; if (streq(target, buf)) { log_debug("preserve already existing symlink '%s' to '%s'", slink, target); - label_fix(slink, true, false); + (void) label_fix(slink, LABEL_IGNORE_ENOENT); utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW); goto exit; } @@ -324,7 +324,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply, /* set the defaults */ if (!selinux) - mac_selinux_fix(devnode, true, false); + (void) mac_selinux_fix(devnode, LABEL_IGNORE_ENOENT); if (!smack) mac_smack_apply(devnode, SMACK_ATTR_ACCESS, NULL); } diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index dc3ae7484d..3a5b138b31 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -680,7 +680,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { rc = EXIT_FAILURE; } - label_fix(hwdb_bin, false, false); + (void) label_fix(hwdb_bin, 0); } if (test) { |