chiark / gitweb /
selinux: rework label query APIs
authorLennart Poettering <lennart@poettering.net>
Thu, 23 Oct 2014 16:58:18 +0000 (18:58 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 23 Oct 2014 19:36:56 +0000 (21:36 +0200)
APIs that query and return something cannot silently fail, they must
either return something useful, or an error. Fix that.

Also, properly rollback socket unit fd creation when something goes
wrong with the security framework.

src/core/socket.c
src/shared/selinux-util.c

index 780015012f7cbcf934be7b7c3bd90422e12c06d3..e9cf7b3e933c8a1b40831b91389f7e0d6a8a5797 100644 (file)
@@ -1139,22 +1139,33 @@ static int socket_open_fds(Socket *s) {
                         continue;
 
                 if (p->type == SOCKET_SOCKET) {
-                        if (!know_label && s->selinux_context_from_net) {
-                                r = mac_selinux_get_our_label(&label);
-                                if (r < 0)
-                                        return r;
-                                know_label = true;
-                        } else if (!know_label) {
 
-                                r = socket_instantiate_service(s);
-                                if (r < 0)
-                                        return r;
+                        if (!know_label) {
+                                /* Figure out label, if we don't it know
+                                 * yet. We do it once, for the first
+                                 * socket where we need this and
+                                 * remember it for the rest. */
+
+                                if (s->selinux_context_from_net) {
+                                        /* Get it from the network label */
+
+                                        r = mac_selinux_get_our_label(&label);
+                                        if (r < 0 && r != EOPNOTSUPP)
+                                                goto rollback;
 
-                                if (UNIT_ISSET(s->service) &&
-                                    SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) {
-                                        r = mac_selinux_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label);
-                                        if (r < 0 && r != -EPERM)
-                                                return r;
+                                } else {
+                                        /* Get it from the executable we are about to start */
+
+                                        r = socket_instantiate_service(s);
+                                        if (r < 0)
+                                                goto rollback;
+
+                                        if (UNIT_ISSET(s->service) &&
+                                            SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) {
+                                                r = mac_selinux_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label);
+                                                if (r < 0 && r != -EPERM && r != EOPNOTSUPP)
+                                                        goto rollback;
+                                        }
                                 }
 
                                 know_label = true;
@@ -1219,6 +1230,7 @@ static int socket_open_fds(Socket *s) {
 rollback:
         socket_close_fds(s);
         mac_selinux_free(label);
+
         return r;
 }
 
index 9707d0cefa903cf92c967ff6a3b78f21906b809d..c59ad31edaef623caa59e19d0db6cdaf822fe530 100644 (file)
@@ -166,34 +166,30 @@ void mac_selinux_finish(void) {
 }
 
 int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
-
-        int r = 0;
+        int r = -EOPNOTSUPP;
 
 #ifdef HAVE_SELINUX
         _cleanup_security_context_free_ security_context_t mycon = NULL, fcon = NULL;
         security_class_t sclass;
 
-        if (!mac_selinux_use()) {
-                *label = NULL;
-                return 0;
-        }
+        assert(exe);
+        assert(label);
+
+        if (!mac_selinux_use())
+                return -EOPNOTSUPP;
 
         r = getcon(&mycon);
         if (r < 0)
-                goto fail;
+                return -errno;
 
         r = getfilecon(exe, &fcon);
         if (r < 0)
-                goto fail;
+                return -errno;
 
         sclass = string_to_security_class("process");
         r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
-        if (r == 0)
-                log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
-
-fail:
-        if (r < 0 && security_getenforce() == 1)
-                r = -errno;
+        if (r < 0)
+                return -errno;
 #endif
 
         return r;
@@ -202,14 +198,15 @@ fail:
 int mac_selinux_get_our_label(char **label) {
         int r = -EOPNOTSUPP;
 
+        assert(label);
+
 #ifdef HAVE_SELINUX
-        char *l = NULL;
+        if (!mac_selinux_use())
+                return -EOPNOTSUPP;
 
-        r = getcon(&l);
+        r = getcon(label);
         if (r < 0)
-                return r;
-
-        *label = l;
+                return -errno;
 #endif
 
         return r;
@@ -219,91 +216,65 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, char **label
         int r = -EOPNOTSUPP;
 
 #ifdef HAVE_SELINUX
-
-        _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL, ret = NULL;
+        _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL;
         _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
         security_class_t sclass;
-
         const char *range = NULL;
 
         assert(socket_fd >= 0);
         assert(exe);
         assert(label);
 
+        if (!mac_selinux_use())
+                return -EOPNOTSUPP;
+
         r = getcon(&mycon);
-        if (r < 0) {
-                r = -EINVAL;
-                goto out;
-        }
+        if (r < 0)
+                return -errno;
 
         r = getpeercon(socket_fd, &peercon);
-        if (r < 0) {
-                r = -EINVAL;
-                goto out;
-        }
+        if (r < 0)
+                return -errno;
 
         r = getexeccon(&fcon);
-        if (r < 0) {
-                r = -EINVAL;
-                goto out;
-        }
+        if (r < 0)
+                return -errno;
 
         if (!fcon) {
                 /* If there is no context set for next exec let's use context
                    of target executable */
                 r = getfilecon(exe, &fcon);
-                if (r < 0) {
-                        r = -errno;
-                        goto out;
-                }
+                if (r < 0)
+                        return -errno;
         }
 
         bcon = context_new(mycon);
-        if (!bcon) {
-                r = -ENOMEM;
-                goto out;
-        }
+        if (!bcon)
+                return -ENOMEM;
 
         pcon = context_new(peercon);
-        if (!pcon) {
-                r = -ENOMEM;
-                goto out;
-        }
+        if (!pcon)
+                return -ENOMEM;
 
         range = context_range_get(pcon);
-        if (!range) {
-                r = -errno;
-                goto out;
-        }
+        if (!range)
+                return -errno;
 
         r = context_range_set(bcon, range);
-        if (r) {
-                r = -errno;
-                goto out;
-        }
+        if (r)
+                return -errno;
 
         freecon(mycon);
         mycon = strdup(context_str(bcon));
-        if (!mycon) {
-                r = -errno;
-                goto out;
-        }
+        if (!mycon)
+                return -ENOMEM;
 
         sclass = string_to_security_class("process");
-        r = security_compute_create(mycon, fcon, sclass, &ret);
-        if (r < 0) {
-                r = -EINVAL;
-                goto out;
-        }
-
-        *label = ret;
-        ret = NULL;
-        r = 0;
-
-out:
-        if (r < 0 && security_getenforce() == 1)
-                return r;
+        r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
+        if (r < 0)
+                return -errno;
 #endif
+
         return r;
 }