]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/selinux-util.c
tree-wide: use -EBADF for fd initialization
[thirdparty/systemd.git] / src / shared / selinux-util.c
index 34e78e6792a9b786bd624aabce75a40c359d09f2..a74883ab81ef4c5b2eacfedcfae126ef8cce0444 100644 (file)
@@ -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;
-        }
+static int selinux_fix_fd(
+                int fd,
+                const char *label_path,
+                LabelFixFlags flags) {
 
-        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);
-
-#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))
+                if (getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq_ptr(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 = -EBADF;
+        _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) {
@@ -346,7 +362,7 @@ int mac_selinux_apply_fd(int fd, const char *path, const char *label) {
 
         assert(label);
 
-        if (fsetfilecon(fd, label) < 0)
+        if (setfilecon(FORMAT_PROC_FD_PATH(fd), label) < 0)
                 return log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, strna(path));
 #endif
         return 0;
@@ -356,7 +372,6 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
 #if HAVE_SELINUX
         _cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
         security_class_t sclass;
-        int r;
 
         assert(exe);
         assert(label);
@@ -364,76 +379,75 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
         if (!mac_selinux_use())
                 return -EOPNOTSUPP;
 
-        r = getcon_raw(&mycon);
-        if (r < 0)
+        if (getcon_raw(&mycon) < 0)
                 return -errno;
+        if (!mycon)
+                return -EOPNOTSUPP;
 
-        r = getfilecon_raw(exe, &fcon);
-        if (r < 0)
+        if (getfilecon_raw(exe, &fcon) < 0)
                 return -errno;
+        if (!fcon)
+                return -EOPNOTSUPP;
 
         sclass = string_to_security_class("process");
         if (sclass == 0)
                 return -ENOSYS;
 
-        r = security_compute_create_raw(mycon, fcon, sclass, label);
-        if (r < 0)
-                return -errno;
-
-        return 0;
+        return RET_NERRNO(security_compute_create_raw(mycon, fcon, sclass, label));
 #else
         return -EOPNOTSUPP;
 #endif
 }
 
-int mac_selinux_get_our_label(char **label) {
-#if HAVE_SELINUX
-        int r;
-
-        assert(label);
+int mac_selinux_get_our_label(char **ret) {
+        assert(ret);
 
+#if HAVE_SELINUX
         if (!mac_selinux_use())
                 return -EOPNOTSUPP;
 
-        r = getcon_raw(label);
-        if (r < 0)
+        _cleanup_freecon_ char *con = NULL;
+        if (getcon_raw(&con) < 0)
                 return -errno;
+        if (!con)
+                return -EOPNOTSUPP;
 
+        *ret = TAKE_PTR(con);
         return 0;
 #else
         return -EOPNOTSUPP;
 #endif
 }
 
-int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
+int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **ret_label) {
 #if HAVE_SELINUX
         _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
         _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
+        const char *range = NULL, *bcon_str = NULL;
         security_class_t sclass;
-        const char *range = NULL;
-        int r;
 
         assert(socket_fd >= 0);
         assert(exe);
-        assert(label);
+        assert(ret_label);
 
         if (!mac_selinux_use())
                 return -EOPNOTSUPP;
 
-        r = getcon_raw(&mycon);
-        if (r < 0)
+        if (getcon_raw(&mycon) < 0)
                 return -errno;
+        if (!mycon)
+                return -EOPNOTSUPP;
 
-        r = getpeercon_raw(socket_fd, &peercon);
-        if (r < 0)
+        if (getpeercon_raw(socket_fd, &peercon) < 0)
                 return -errno;
+        if (!peercon)
+                return -EOPNOTSUPP;
 
-        if (!exec_label) {
-                /* If there is no context set for next exec let's use context
-                   of target executable */
-                r = getfilecon_raw(exe, &fcon);
-                if (r < 0)
+        if (!exec_label) { /* If there is no context set for next exec let's use context of target executable */
+                if (getfilecon_raw(exe, &fcon) < 0)
                         return -errno;
+                if (!fcon)
+                        return -EOPNOTSUPP;
         }
 
         bcon = context_new(mycon);
@@ -448,24 +462,18 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
         if (!range)
                 return -errno;
 
-        r = context_range_set(bcon, range);
-        if (r)
+        if (context_range_set(bcon, range) != 0)
                 return -errno;
 
-        freecon(mycon);
-        mycon = strdup(context_str(bcon));
-        if (!mycon)
+        bcon_str = context_str(bcon);
+        if (!bcon_str)
                 return -ENOMEM;
 
         sclass = string_to_security_class("process");
         if (sclass == 0)
                 return -ENOSYS;
 
-        r = security_compute_create_raw(mycon, fcon, sclass, label);
-        if (r < 0)
-                return -errno;
-
-        return 0;
+        return RET_NERRNO(security_compute_create_raw(bcon_str, fcon, sclass, ret_label));
 #else
         return -EOPNOTSUPP;
 #endif
@@ -511,25 +519,30 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
 }
 #endif
 
-int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) {
+int mac_selinux_create_file_prepare_at(
+                int dir_fd,
+                const char *path,
+                mode_t mode) {
+
 #if HAVE_SELINUX
         _cleanup_free_ char *abspath = NULL;
         int r;
 
-        assert(path);
+        if (dir_fd < 0 && dir_fd != AT_FDCWD)
+                return -EBADF;
 
         if (!label_hnd)
                 return 0;
 
-        if (!path_is_absolute(path)) {
-                if (dirfd == AT_FDCWD)
+        if (isempty(path) || !path_is_absolute(path)) {
+                if (dir_fd == AT_FDCWD)
                         r = safe_getcwd(&abspath);
                 else
-                        r = fd_get_path(dirfd, &abspath);
+                        r = fd_get_path(dir_fd, &abspath);
                 if (r < 0)
                         return r;
 
-                if (!path_extend(&abspath, path))
+                if (!isempty(path) && !path_extend(&abspath, path))
                         return -ENOMEM;
 
                 path = abspath;
@@ -541,25 +554,19 @@ int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode)
 #endif
 }
 
-int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
+int mac_selinux_create_file_prepare_label(const char *path, const char *label) {
 #if HAVE_SELINUX
-        int r;
-
-        _cleanup_free_ char *abspath = NULL;
-
-        assert(path);
 
-        if (!label_hnd)
+        if (!label)
                 return 0;
 
-        r = path_make_absolute_cwd(path, &abspath);
-        if (r < 0)
-                return r;
+        if (!mac_selinux_use())
+                return 0;
 
-        return selinux_create_file_prepare_abspath(abspath, mode);
-#else
-        return 0;
+        if (setfscreatecon_raw(label) < 0)
+                return log_enforcing_errno(errno, "Failed to set specified SELinux security context '%s' for '%s': %m", label, strna(path));
 #endif
+        return 0;
 }
 
 void mac_selinux_create_file_clear(void) {
@@ -609,6 +616,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
         _cleanup_freecon_ char *fcon = NULL;
         const struct sockaddr_un *un;
         bool context_changed = false;
+        size_t sz;
         char *path;
         int r;
 
@@ -632,7 +640,10 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
         if (un->sun_path[0] == 0)
                 goto skipped;
 
-        path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
+        sz = addrlen - offsetof(struct sockaddr_un, sun_path);
+        if (sz > PATH_MAX)
+                goto skipped;
+        path = strndupa_safe(un->sun_path, sz);
 
         /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
         mac_selinux_maybe_reload();
@@ -668,7 +679,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
                         context_changed = true;
         }
 
-        r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
+        r = RET_NERRNO(bind(fd, addr, addrlen));
 
         if (context_changed)
                 (void) setfscreatecon_raw(NULL);
@@ -677,8 +688,5 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
 
 skipped:
 #endif
-        if (bind(fd, addr, addrlen) < 0)
-                return -errno;
-
-        return 0;
+        return RET_NERRNO(bind(fd, addr, addrlen));
 }