LCOV - code coverage report
Current view: top level - basic - selinux-util.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 7 36 19.4 %
Date: 2015-07-29 18:47:03 Functions: 3 15 20.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2010 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <malloc.h>
      24             : #include <sys/un.h>
      25             : 
      26             : #ifdef HAVE_SELINUX
      27             : #include <selinux/selinux.h>
      28             : #include <selinux/label.h>
      29             : #include <selinux/context.h>
      30             : #endif
      31             : 
      32             : #include "strv.h"
      33             : #include "path-util.h"
      34             : #include "selinux-util.h"
      35             : 
      36             : #ifdef HAVE_SELINUX
      37             : DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon);
      38             : DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
      39             : 
      40             : #define _cleanup_security_context_free_ _cleanup_(freeconp)
      41             : #define _cleanup_context_free_ _cleanup_(context_freep)
      42             : 
      43             : static int cached_use = -1;
      44             : static struct selabel_handle *label_hnd = NULL;
      45             : 
      46             : #define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__)
      47             : #endif
      48             : 
      49           2 : bool mac_selinux_use(void) {
      50             : #ifdef HAVE_SELINUX
      51             :         if (cached_use < 0)
      52             :                 cached_use = is_selinux_enabled() > 0;
      53             : 
      54             :         return cached_use;
      55             : #else
      56           2 :         return false;
      57             : #endif
      58             : }
      59             : 
      60           0 : void mac_selinux_retest(void) {
      61             : #ifdef HAVE_SELINUX
      62             :         cached_use = -1;
      63             : #endif
      64           0 : }
      65             : 
      66           0 : int mac_selinux_init(const char *prefix) {
      67           0 :         int r = 0;
      68             : 
      69             : #ifdef HAVE_SELINUX
      70             :         usec_t before_timestamp, after_timestamp;
      71             :         struct mallinfo before_mallinfo, after_mallinfo;
      72             : 
      73             :         if (!mac_selinux_use())
      74             :                 return 0;
      75             : 
      76             :         if (label_hnd)
      77             :                 return 0;
      78             : 
      79             :         before_mallinfo = mallinfo();
      80             :         before_timestamp = now(CLOCK_MONOTONIC);
      81             : 
      82             :         if (prefix) {
      83             :                 struct selinux_opt options[] = {
      84             :                         { .type = SELABEL_OPT_SUBSET, .value = prefix },
      85             :                 };
      86             : 
      87             :                 label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
      88             :         } else
      89             :                 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
      90             : 
      91             :         if (!label_hnd) {
      92             :                 log_enforcing("Failed to initialize SELinux context: %m");
      93             :                 r = security_getenforce() == 1 ? -errno : 0;
      94             :         } else  {
      95             :                 char timespan[FORMAT_TIMESPAN_MAX];
      96             :                 int l;
      97             : 
      98             :                 after_timestamp = now(CLOCK_MONOTONIC);
      99             :                 after_mallinfo = mallinfo();
     100             : 
     101             :                 l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
     102             : 
     103             :                 log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
     104             :                           format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
     105             :                           (l+1023)/1024);
     106             :         }
     107             : #endif
     108             : 
     109           0 :         return r;
     110             : }
     111             : 
     112           0 : void mac_selinux_finish(void) {
     113             : 
     114             : #ifdef HAVE_SELINUX
     115             :         if (!label_hnd)
     116             :                 return;
     117             : 
     118             :         selabel_close(label_hnd);
     119             :         label_hnd = NULL;
     120             : #endif
     121           0 : }
     122             : 
     123           0 : int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
     124             : 
     125             : #ifdef HAVE_SELINUX
     126             :         struct stat st;
     127             :         int r;
     128             : 
     129             :         assert(path);
     130             : 
     131             :         /* if mac_selinux_init() wasn't called before we are a NOOP */
     132             :         if (!label_hnd)
     133             :                 return 0;
     134             : 
     135             :         r = lstat(path, &st);
     136             :         if (r >= 0) {
     137             :                 _cleanup_security_context_free_ security_context_t fcon = NULL;
     138             : 
     139             :                 r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
     140             : 
     141             :                 /* If there's no label to set, then exit without warning */
     142             :                 if (r < 0 && errno == ENOENT)
     143             :                         return 0;
     144             : 
     145             :                 if (r >= 0) {
     146             :                         r = lsetfilecon(path, fcon);
     147             : 
     148             :                         /* If the FS doesn't support labels, then exit without warning */
     149             :                         if (r < 0 && errno == EOPNOTSUPP)
     150             :                                 return 0;
     151             :                 }
     152             :         }
     153             : 
     154             :         if (r < 0) {
     155             :                 /* Ignore ENOENT in some cases */
     156             :                 if (ignore_enoent && errno == ENOENT)
     157             :                         return 0;
     158             : 
     159             :                 if (ignore_erofs && errno == EROFS)
     160             :                         return 0;
     161             : 
     162             :                 log_enforcing("Unable to fix SELinux security context of %s: %m", path);
     163             :                 if (security_getenforce() == 1)
     164             :                         return -errno;
     165             :         }
     166             : #endif
     167             : 
     168           0 :         return 0;
     169             : }
     170             : 
     171           0 : int mac_selinux_apply(const char *path, const char *label) {
     172             : 
     173             : #ifdef HAVE_SELINUX
     174             :         assert(path);
     175             :         assert(label);
     176             : 
     177             :         if (!mac_selinux_use())
     178             :                 return 0;
     179             : 
     180             :         if (setfilecon(path, (security_context_t) label) < 0) {
     181             :                 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
     182             :                 if (security_getenforce() == 1)
     183             :                         return -errno;
     184             :         }
     185             : #endif
     186           0 :         return 0;
     187             : }
     188             : 
     189           0 : int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
     190           0 :         int r = -EOPNOTSUPP;
     191             : 
     192             : #ifdef HAVE_SELINUX
     193             :         _cleanup_security_context_free_ security_context_t mycon = NULL, fcon = NULL;
     194             :         security_class_t sclass;
     195             : 
     196             :         assert(exe);
     197             :         assert(label);
     198             : 
     199             :         if (!mac_selinux_use())
     200             :                 return -EOPNOTSUPP;
     201             : 
     202             :         r = getcon(&mycon);
     203             :         if (r < 0)
     204             :                 return -errno;
     205             : 
     206             :         r = getfilecon(exe, &fcon);
     207             :         if (r < 0)
     208             :                 return -errno;
     209             : 
     210             :         sclass = string_to_security_class("process");
     211             :         r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
     212             :         if (r < 0)
     213             :                 return -errno;
     214             : #endif
     215             : 
     216           0 :         return r;
     217             : }
     218             : 
     219           0 : int mac_selinux_get_our_label(char **label) {
     220           0 :         int r = -EOPNOTSUPP;
     221             : 
     222           0 :         assert(label);
     223             : 
     224             : #ifdef HAVE_SELINUX
     225             :         if (!mac_selinux_use())
     226             :                 return -EOPNOTSUPP;
     227             : 
     228             :         r = getcon(label);
     229             :         if (r < 0)
     230             :                 return -errno;
     231             : #endif
     232             : 
     233           0 :         return r;
     234             : }
     235             : 
     236           0 : int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
     237           0 :         int r = -EOPNOTSUPP;
     238             : 
     239             : #ifdef HAVE_SELINUX
     240             :         _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL;
     241             :         _cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
     242             :         security_class_t sclass;
     243             :         const char *range = NULL;
     244             : 
     245             :         assert(socket_fd >= 0);
     246             :         assert(exe);
     247             :         assert(label);
     248             : 
     249             :         if (!mac_selinux_use())
     250             :                 return -EOPNOTSUPP;
     251             : 
     252             :         r = getcon(&mycon);
     253             :         if (r < 0)
     254             :                 return -errno;
     255             : 
     256             :         r = getpeercon(socket_fd, &peercon);
     257             :         if (r < 0)
     258             :                 return -errno;
     259             : 
     260             :         if (!exec_label) {
     261             :                 /* If there is no context set for next exec let's use context
     262             :                    of target executable */
     263             :                 r = getfilecon(exe, &fcon);
     264             :                 if (r < 0)
     265             :                         return -errno;
     266             :         }
     267             : 
     268             :         bcon = context_new(mycon);
     269             :         if (!bcon)
     270             :                 return -ENOMEM;
     271             : 
     272             :         pcon = context_new(peercon);
     273             :         if (!pcon)
     274             :                 return -ENOMEM;
     275             : 
     276             :         range = context_range_get(pcon);
     277             :         if (!range)
     278             :                 return -errno;
     279             : 
     280             :         r = context_range_set(bcon, range);
     281             :         if (r)
     282             :                 return -errno;
     283             : 
     284             :         freecon(mycon);
     285             :         mycon = strdup(context_str(bcon));
     286             :         if (!mycon)
     287             :                 return -ENOMEM;
     288             : 
     289             :         sclass = string_to_security_class("process");
     290             :         r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
     291             :         if (r < 0)
     292             :                 return -errno;
     293             : #endif
     294             : 
     295           0 :         return r;
     296             : }
     297             : 
     298           0 : void mac_selinux_free(char *label) {
     299             : 
     300             : #ifdef HAVE_SELINUX
     301             :         if (!mac_selinux_use())
     302             :                 return;
     303             : 
     304             :         freecon((security_context_t) label);
     305             : #endif
     306           0 : }
     307             : 
     308          75 : int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
     309          75 :         int r = 0;
     310             : 
     311             : #ifdef HAVE_SELINUX
     312             :         _cleanup_security_context_free_ security_context_t filecon = NULL;
     313             : 
     314             :         assert(path);
     315             : 
     316             :         if (!label_hnd)
     317             :                 return 0;
     318             : 
     319             :         if (path_is_absolute(path))
     320             :                 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
     321             :         else {
     322             :                 _cleanup_free_ char *newpath;
     323             : 
     324             :                 newpath = path_make_absolute_cwd(path);
     325             :                 if (!newpath)
     326             :                         return -ENOMEM;
     327             : 
     328             :                 r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
     329             :         }
     330             : 
     331             :         /* No context specified by the policy? Proceed without setting it. */
     332             :         if (r < 0 && errno == ENOENT)
     333             :                 return 0;
     334             : 
     335             :         if (r < 0)
     336             :                 r = -errno;
     337             :         else {
     338             :                 r = setfscreatecon(filecon);
     339             :                 if (r < 0) {
     340             :                         log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
     341             :                         r = -errno;
     342             :                 }
     343             :         }
     344             : 
     345             :         if (r < 0 && security_getenforce() == 0)
     346             :                 r = 0;
     347             : #endif
     348             : 
     349          75 :         return r;
     350             : }
     351             : 
     352          75 : void mac_selinux_create_file_clear(void) {
     353             : 
     354             : #ifdef HAVE_SELINUX
     355             :         PROTECT_ERRNO;
     356             : 
     357             :         if (!mac_selinux_use())
     358             :                 return;
     359             : 
     360             :         setfscreatecon(NULL);
     361             : #endif
     362          75 : }
     363             : 
     364           0 : int mac_selinux_create_socket_prepare(const char *label) {
     365             : 
     366             : #ifdef HAVE_SELINUX
     367             :         if (!mac_selinux_use())
     368             :                 return 0;
     369             : 
     370             :         assert(label);
     371             : 
     372             :         if (setsockcreatecon((security_context_t) label) < 0) {
     373             :                 log_enforcing("Failed to set SELinux security context %s for sockets: %m", label);
     374             : 
     375             :                 if (security_getenforce() == 1)
     376             :                         return -errno;
     377             :         }
     378             : #endif
     379             : 
     380           0 :         return 0;
     381             : }
     382             : 
     383           0 : void mac_selinux_create_socket_clear(void) {
     384             : 
     385             : #ifdef HAVE_SELINUX
     386             :         PROTECT_ERRNO;
     387             : 
     388             :         if (!mac_selinux_use())
     389             :                 return;
     390             : 
     391             :         setsockcreatecon(NULL);
     392             : #endif
     393           0 : }
     394             : 
     395           0 : int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
     396             : 
     397             :         /* Binds a socket and label its file system object according to the SELinux policy */
     398             : 
     399             : #ifdef HAVE_SELINUX
     400             :         _cleanup_security_context_free_ security_context_t fcon = NULL;
     401             :         const struct sockaddr_un *un;
     402             :         char *path;
     403             :         int r;
     404             : 
     405             :         assert(fd >= 0);
     406             :         assert(addr);
     407             :         assert(addrlen >= sizeof(sa_family_t));
     408             : 
     409             :         if (!label_hnd)
     410             :                 goto skipped;
     411             : 
     412             :         /* Filter out non-local sockets */
     413             :         if (addr->sa_family != AF_UNIX)
     414             :                 goto skipped;
     415             : 
     416             :         /* Filter out anonymous sockets */
     417             :         if (addrlen < sizeof(sa_family_t) + 1)
     418             :                 goto skipped;
     419             : 
     420             :         /* Filter out abstract namespace sockets */
     421             :         un = (const struct sockaddr_un*) addr;
     422             :         if (un->sun_path[0] == 0)
     423             :                 goto skipped;
     424             : 
     425             :         path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
     426             : 
     427             :         if (path_is_absolute(path))
     428             :                 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
     429             :         else {
     430             :                 _cleanup_free_ char *newpath;
     431             : 
     432             :                 newpath = path_make_absolute_cwd(path);
     433             :                 if (!newpath)
     434             :                         return -ENOMEM;
     435             : 
     436             :                 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
     437             :         }
     438             : 
     439             :         if (r == 0)
     440             :                 r = setfscreatecon(fcon);
     441             : 
     442             :         if (r < 0 && errno != ENOENT) {
     443             :                 log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
     444             : 
     445             :                 if (security_getenforce() == 1) {
     446             :                         r = -errno;
     447             :                         goto finish;
     448             :                 }
     449             :         }
     450             : 
     451             :         r = bind(fd, addr, addrlen);
     452             :         if (r < 0)
     453             :                 r = -errno;
     454             : 
     455             : finish:
     456             :         setfscreatecon(NULL);
     457             :         return r;
     458             : 
     459             : skipped:
     460             : #endif
     461           0 :         return bind(fd, addr, addrlen) < 0 ? -errno : 0;
     462             : }

Generated by: LCOV version 1.11