LCOV - code coverage report
Current view: top level - core - smack-setup.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 230 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 6 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 268 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : /***
       3                 :            :   Copyright © 2013 Intel Corporation
       4                 :            :   Authors:
       5                 :            :         Nathaniel Chen <nathaniel.chen@intel.com>
       6                 :            : ***/
       7                 :            : 
       8                 :            : #include <dirent.h>
       9                 :            : #include <errno.h>
      10                 :            : #include <fcntl.h>
      11                 :            : #include <stdio.h>
      12                 :            : #include <stdlib.h>
      13                 :            : #include <string.h>
      14                 :            : #include <unistd.h>
      15                 :            : 
      16                 :            : #include "alloc-util.h"
      17                 :            : #include "dirent-util.h"
      18                 :            : #include "fd-util.h"
      19                 :            : #include "fileio.h"
      20                 :            : #include "log.h"
      21                 :            : #include "macro.h"
      22                 :            : #include "smack-setup.h"
      23                 :            : #include "string-util.h"
      24                 :            : #include "util.h"
      25                 :            : 
      26                 :            : #if ENABLE_SMACK
      27                 :            : 
      28                 :          0 : static int fdopen_unlocked_at(int dfd, const char *dir, const char *name, int *status, FILE **ret_file) {
      29                 :            :         int fd, r;
      30                 :            :         FILE *f;
      31                 :            : 
      32                 :          0 :         fd = openat(dfd, name, O_RDONLY|O_CLOEXEC);
      33         [ #  # ]:          0 :         if (fd < 0) {
      34         [ #  # ]:          0 :                 if (*status == 0)
      35                 :          0 :                         *status = -errno;
      36                 :            : 
      37         [ #  # ]:          0 :                 return log_warning_errno(errno, "Failed to open \"%s/%s\": %m", dir, name);
      38                 :            :         }
      39                 :            : 
      40                 :          0 :         r = fdopen_unlocked(fd, "r", &f);
      41         [ #  # ]:          0 :         if (r < 0) {
      42         [ #  # ]:          0 :                 if (*status == 0)
      43                 :          0 :                         *status = r;
      44                 :            : 
      45                 :          0 :                 safe_close(fd);
      46         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to open \"%s/%s\": %m", dir, name);
      47                 :            :         }
      48                 :            : 
      49                 :          0 :         *ret_file = f;
      50                 :          0 :         return 0;
      51                 :            : }
      52                 :            : 
      53                 :          0 : static int write_access2_rules(const char *srcdir) {
      54                 :          0 :         _cleanup_close_ int load2_fd = -1, change_fd = -1;
      55                 :          0 :         _cleanup_closedir_ DIR *dir = NULL;
      56                 :            :         struct dirent *entry;
      57                 :          0 :         int dfd = -1, r = 0;
      58                 :            : 
      59                 :          0 :         load2_fd = open("/sys/fs/smackfs/load2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
      60         [ #  # ]:          0 :         if (load2_fd < 0)  {
      61         [ #  # ]:          0 :                 if (errno != ENOENT)
      62         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/load2': %m");
      63                 :          0 :                 return -errno; /* negative error */
      64                 :            :         }
      65                 :            : 
      66                 :          0 :         change_fd = open("/sys/fs/smackfs/change-rule", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
      67         [ #  # ]:          0 :         if (change_fd < 0)  {
      68         [ #  # ]:          0 :                 if (errno != ENOENT)
      69         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/change-rule': %m");
      70                 :          0 :                 return -errno; /* negative error */
      71                 :            :         }
      72                 :            : 
      73                 :            :         /* write rules to load2 or change-rule from every file in the directory */
      74                 :          0 :         dir = opendir(srcdir);
      75         [ #  # ]:          0 :         if (!dir) {
      76         [ #  # ]:          0 :                 if (errno != ENOENT)
      77         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to opendir '%s': %m", srcdir);
      78                 :          0 :                 return errno; /* positive on purpose */
      79                 :            :         }
      80                 :            : 
      81                 :          0 :         dfd = dirfd(dir);
      82         [ #  # ]:          0 :         assert(dfd >= 0);
      83                 :            : 
      84   [ #  #  #  #  :          0 :         FOREACH_DIRENT(entry, dir, return 0) {
                   #  # ]
      85      [ #  #  # ]:          0 :                 _cleanup_fclose_ FILE *policy = NULL;
      86                 :            : 
      87         [ #  # ]:          0 :                 if (!dirent_is_file(entry))
      88                 :          0 :                         continue;
      89                 :            : 
      90         [ #  # ]:          0 :                 if (fdopen_unlocked_at(dfd, srcdir, entry->d_name, &r, &policy) < 0)
      91                 :          0 :                         continue;
      92                 :            : 
      93                 :            :                 /* load2 write rules in the kernel require a line buffered stream */
      94                 :          0 :                 for (;;) {
      95   [ #  #  #  #  :          0 :                         _cleanup_free_ char *buf = NULL, *sbj = NULL, *obj = NULL, *acc1 = NULL, *acc2 = NULL;
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
      96                 :            :                         int q;
      97                 :            : 
      98                 :          0 :                         q = read_line(policy, NAME_MAX, &buf);
      99         [ #  # ]:          0 :                         if (q < 0)
     100         [ #  # ]:          0 :                                 return log_error_errno(q, "Failed to read line from '%s': %m", entry->d_name);
     101         [ #  # ]:          0 :                         if (q == 0)
     102                 :          0 :                                 break;
     103                 :            : 
     104   [ #  #  #  # ]:          0 :                         if (isempty(buf) || strchr(COMMENTS, buf[0]))
     105                 :          0 :                                 continue;
     106                 :            : 
     107                 :            :                         /* if 3 args -> load rule   : subject object access1 */
     108                 :            :                         /* if 4 args -> change rule : subject object access1 access2 */
     109         [ #  # ]:          0 :                         if (sscanf(buf, "%ms %ms %ms %ms", &sbj, &obj, &acc1, &acc2) < 3) {
     110         [ #  # ]:          0 :                                 log_error_errno(errno, "Failed to parse rule '%s' in '%s', ignoring.", buf, entry->d_name);
     111                 :          0 :                                 continue;
     112                 :            :                         }
     113                 :            : 
     114   [ #  #  #  # ]:          0 :                         if (write(isempty(acc2) ? load2_fd : change_fd, buf, strlen(buf)) < 0) {
     115         [ #  # ]:          0 :                                 if (r == 0)
     116                 :          0 :                                         r = -errno;
     117   [ #  #  #  # ]:          0 :                                 log_error_errno(errno, "Failed to write '%s' to '%s' in '%s': %m",
     118                 :            :                                                 buf, isempty(acc2) ? "/sys/fs/smackfs/load2" : "/sys/fs/smackfs/change-rule", entry->d_name);
     119                 :            :                         }
     120                 :            :                 }
     121                 :            :         }
     122                 :            : 
     123                 :          0 :         return r;
     124                 :            : }
     125                 :            : 
     126                 :          0 : static int write_cipso2_rules(const char *srcdir) {
     127                 :          0 :         _cleanup_close_ int cipso2_fd = -1;
     128                 :          0 :         _cleanup_closedir_ DIR *dir = NULL;
     129                 :            :         struct dirent *entry;
     130                 :          0 :         int dfd = -1, r = 0;
     131                 :            : 
     132                 :          0 :         cipso2_fd = open("/sys/fs/smackfs/cipso2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
     133         [ #  # ]:          0 :         if (cipso2_fd < 0)  {
     134         [ #  # ]:          0 :                 if (errno != ENOENT)
     135         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/cipso2': %m");
     136                 :          0 :                 return -errno; /* negative error */
     137                 :            :         }
     138                 :            : 
     139                 :            :         /* write rules to cipso2 from every file in the directory */
     140                 :          0 :         dir = opendir(srcdir);
     141         [ #  # ]:          0 :         if (!dir) {
     142         [ #  # ]:          0 :                 if (errno != ENOENT)
     143         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to opendir '%s': %m", srcdir);
     144                 :          0 :                 return errno; /* positive on purpose */
     145                 :            :         }
     146                 :            : 
     147                 :          0 :         dfd = dirfd(dir);
     148         [ #  # ]:          0 :         assert(dfd >= 0);
     149                 :            : 
     150   [ #  #  #  #  :          0 :         FOREACH_DIRENT(entry, dir, return 0) {
                   #  # ]
     151      [ #  #  # ]:          0 :                 _cleanup_fclose_ FILE *policy = NULL;
     152                 :            : 
     153         [ #  # ]:          0 :                 if (!dirent_is_file(entry))
     154                 :          0 :                         continue;
     155                 :            : 
     156         [ #  # ]:          0 :                 if (fdopen_unlocked_at(dfd, srcdir, entry->d_name, &r, &policy) < 0)
     157                 :          0 :                         continue;
     158                 :            : 
     159                 :            :                 /* cipso2 write rules in the kernel require a line buffered stream */
     160                 :          0 :                 for (;;) {
     161   [ #  #  #  # ]:          0 :                         _cleanup_free_ char *buf = NULL;
     162                 :            :                         int q;
     163                 :            : 
     164                 :          0 :                         q = read_line(policy, NAME_MAX, &buf);
     165         [ #  # ]:          0 :                         if (q < 0)
     166         [ #  # ]:          0 :                                 return log_error_errno(q, "Failed to read line from '%s': %m", entry->d_name);
     167         [ #  # ]:          0 :                         if (q == 0)
     168                 :          0 :                                 break;
     169                 :            : 
     170   [ #  #  #  # ]:          0 :                         if (isempty(buf) || strchr(COMMENTS, buf[0]))
     171                 :          0 :                                 continue;
     172                 :            : 
     173         [ #  # ]:          0 :                         if (write(cipso2_fd, buf, strlen(buf)) < 0) {
     174         [ #  # ]:          0 :                                 if (r == 0)
     175                 :          0 :                                         r = -errno;
     176         [ #  # ]:          0 :                                 log_error_errno(errno, "Failed to write '%s' to '/sys/fs/smackfs/cipso2' in '%s': %m",
     177                 :            :                                                 buf, entry->d_name);
     178                 :          0 :                                 break;
     179                 :            :                         }
     180                 :            :                 }
     181                 :            :         }
     182                 :            : 
     183                 :          0 :         return r;
     184                 :            : }
     185                 :            : 
     186                 :          0 : static int write_netlabel_rules(const char *srcdir) {
     187                 :          0 :         _cleanup_fclose_ FILE *dst = NULL;
     188                 :          0 :         _cleanup_closedir_ DIR *dir = NULL;
     189                 :            :         struct dirent *entry;
     190                 :          0 :         int dfd = -1, r = 0;
     191                 :            : 
     192                 :          0 :         dst = fopen("/sys/fs/smackfs/netlabel", "we");
     193         [ #  # ]:          0 :         if (!dst)  {
     194         [ #  # ]:          0 :                 if (errno != ENOENT)
     195         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to open /sys/fs/smackfs/netlabel: %m");
     196                 :          0 :                 return -errno; /* negative error */
     197                 :            :         }
     198                 :            : 
     199                 :            :         /* write rules to dst from every file in the directory */
     200                 :          0 :         dir = opendir(srcdir);
     201         [ #  # ]:          0 :         if (!dir) {
     202         [ #  # ]:          0 :                 if (errno != ENOENT)
     203         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to opendir %s: %m", srcdir);
     204                 :          0 :                 return errno; /* positive on purpose */
     205                 :            :         }
     206                 :            : 
     207                 :          0 :         dfd = dirfd(dir);
     208         [ #  # ]:          0 :         assert(dfd >= 0);
     209                 :            : 
     210   [ #  #  #  #  :          0 :         FOREACH_DIRENT(entry, dir, return 0) {
                   #  # ]
     211      [ #  #  # ]:          0 :                 _cleanup_fclose_ FILE *policy = NULL;
     212                 :            : 
     213         [ #  # ]:          0 :                 if (fdopen_unlocked_at(dfd, srcdir, entry->d_name, &r, &policy) < 0)
     214                 :          0 :                         continue;
     215                 :            : 
     216                 :            :                 /* load2 write rules in the kernel require a line buffered stream */
     217                 :          0 :                 for (;;) {
     218      [ #  #  # ]:          0 :                         _cleanup_free_ char *buf = NULL;
     219                 :            :                         int q;
     220                 :            : 
     221                 :          0 :                         q = read_line(policy, NAME_MAX, &buf);
     222         [ #  # ]:          0 :                         if (q < 0)
     223         [ #  # ]:          0 :                                 return log_error_errno(q, "Failed to read line from %s: %m", entry->d_name);
     224         [ #  # ]:          0 :                         if (q == 0)
     225                 :          0 :                                 break;
     226                 :            : 
     227         [ #  # ]:          0 :                         if (!fputs(buf, dst)) {
     228         [ #  # ]:          0 :                                 if (r == 0)
     229                 :          0 :                                         r = -EINVAL;
     230         [ #  # ]:          0 :                                 log_error_errno(errno, "Failed to write line to /sys/fs/smackfs/netlabel: %m");
     231                 :          0 :                                 break;
     232                 :            :                         }
     233                 :          0 :                         q = fflush_and_check(dst);
     234         [ #  # ]:          0 :                         if (q < 0) {
     235         [ #  # ]:          0 :                                 if (r == 0)
     236                 :          0 :                                         r = q;
     237         [ #  # ]:          0 :                                 log_error_errno(q, "Failed to flush writes to /sys/fs/smackfs/netlabel: %m");
     238                 :          0 :                                 break;
     239                 :            :                         }
     240                 :            :                 }
     241                 :            :         }
     242                 :            : 
     243                 :          0 :         return r;
     244                 :            : }
     245                 :            : 
     246                 :          0 : static int write_onlycap_list(void) {
     247                 :          0 :         _cleanup_close_ int onlycap_fd = -1;
     248                 :          0 :         _cleanup_free_ char *list = NULL;
     249                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     250                 :          0 :         size_t len = 0, allocated = 0;
     251                 :            :         int r;
     252                 :            : 
     253                 :          0 :         f = fopen("/etc/smack/onlycap", "re");
     254         [ #  # ]:          0 :         if (!f) {
     255         [ #  # ]:          0 :                 if (errno != ENOENT)
     256         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to read '/etc/smack/onlycap': %m");
     257                 :            : 
     258         [ #  # ]:          0 :                 return errno == ENOENT ? ENOENT : -errno;
     259                 :            :         }
     260                 :            : 
     261                 :          0 :         for (;;) {
     262   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *buf = NULL;
     263                 :            :                 size_t l;
     264                 :            : 
     265                 :          0 :                 r = read_line(f, LONG_LINE_MAX, &buf);
     266         [ #  # ]:          0 :                 if (r < 0)
     267         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to read line from /etc/smack/onlycap: %m");
     268         [ #  # ]:          0 :                 if (r == 0)
     269                 :          0 :                         break;
     270                 :            : 
     271   [ #  #  #  # ]:          0 :                 if (isempty(buf) || strchr(COMMENTS, *buf))
     272                 :          0 :                         continue;
     273                 :            : 
     274                 :          0 :                 l = strlen(buf);
     275         [ #  # ]:          0 :                 if (!GREEDY_REALLOC(list, allocated, len + l + 1))
     276                 :          0 :                         return log_oom();
     277                 :            : 
     278                 :          0 :                 stpcpy(list + len, buf)[0] = ' ';
     279                 :          0 :                 len += l + 1;
     280                 :            :         }
     281                 :            : 
     282         [ #  # ]:          0 :         if (len == 0)
     283                 :          0 :                 return 0;
     284                 :            : 
     285                 :          0 :         list[len - 1] = 0;
     286                 :            : 
     287                 :          0 :         onlycap_fd = open("/sys/fs/smackfs/onlycap", O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
     288         [ #  # ]:          0 :         if (onlycap_fd < 0) {
     289         [ #  # ]:          0 :                 if (errno != ENOENT)
     290         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/onlycap': %m");
     291                 :          0 :                 return -errno; /* negative error */
     292                 :            :         }
     293                 :            : 
     294                 :          0 :         r = write(onlycap_fd, list, len);
     295         [ #  # ]:          0 :         if (r < 0)
     296         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to write onlycap list(%s) to '/sys/fs/smackfs/onlycap': %m", list);
     297                 :            : 
     298                 :          0 :         return 0;
     299                 :            : }
     300                 :            : 
     301                 :            : #endif
     302                 :            : 
     303                 :          0 : int mac_smack_setup(bool *loaded_policy) {
     304                 :            : 
     305                 :            : #if ENABLE_SMACK
     306                 :            : 
     307                 :            :         int r;
     308                 :            : 
     309         [ #  # ]:          0 :         assert(loaded_policy);
     310                 :            : 
     311                 :          0 :         r = write_access2_rules("/etc/smack/accesses.d/");
     312   [ #  #  #  # ]:          0 :         switch(r) {
     313                 :          0 :         case -ENOENT:
     314         [ #  # ]:          0 :                 log_debug("Smack is not enabled in the kernel.");
     315                 :          0 :                 return 0;
     316                 :          0 :         case ENOENT:
     317         [ #  # ]:          0 :                 log_debug("Smack access rules directory '/etc/smack/accesses.d/' not found");
     318                 :          0 :                 return 0;
     319                 :          0 :         case 0:
     320         [ #  # ]:          0 :                 log_info("Successfully loaded Smack policies.");
     321                 :          0 :                 break;
     322                 :          0 :         default:
     323         [ #  # ]:          0 :                 log_warning_errno(r, "Failed to load Smack access rules, ignoring: %m");
     324                 :          0 :                 return 0;
     325                 :            :         }
     326                 :            : 
     327                 :            : #ifdef SMACK_RUN_LABEL
     328                 :            :         r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER);
     329                 :            :         if (r < 0)
     330                 :            :                 log_warning_errno(r, "Failed to set SMACK label \"" SMACK_RUN_LABEL "\" on self: %m");
     331                 :            :         r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER);
     332                 :            :         if (r < 0)
     333                 :            :                 log_warning_errno(r, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL "\": %m");
     334                 :            :         r = write_string_file("/sys/fs/smackfs/netlabel",
     335                 :            :                               "0.0.0.0/0 " SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER);
     336                 :            :         if (r < 0)
     337                 :            :                 log_warning_errno(r, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL "\": %m");
     338                 :            :         r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", WRITE_STRING_FILE_DISABLE_BUFFER);
     339                 :            :         if (r < 0)
     340                 :            :                 log_warning_errno(r, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m");
     341                 :            : #endif
     342                 :            : 
     343                 :          0 :         r = write_cipso2_rules("/etc/smack/cipso.d/");
     344   [ #  #  #  # ]:          0 :         switch(r) {
     345                 :          0 :         case -ENOENT:
     346         [ #  # ]:          0 :                 log_debug("Smack/CIPSO is not enabled in the kernel.");
     347                 :          0 :                 return 0;
     348                 :          0 :         case ENOENT:
     349         [ #  # ]:          0 :                 log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
     350                 :          0 :                 break;
     351                 :          0 :         case 0:
     352         [ #  # ]:          0 :                 log_info("Successfully loaded Smack/CIPSO policies.");
     353                 :          0 :                 break;
     354                 :          0 :         default:
     355         [ #  # ]:          0 :                 log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m");
     356                 :          0 :                 break;
     357                 :            :         }
     358                 :            : 
     359                 :          0 :         r = write_netlabel_rules("/etc/smack/netlabel.d/");
     360   [ #  #  #  # ]:          0 :         switch(r) {
     361                 :          0 :         case -ENOENT:
     362         [ #  # ]:          0 :                 log_debug("Smack/CIPSO is not enabled in the kernel.");
     363                 :          0 :                 return 0;
     364                 :          0 :         case ENOENT:
     365         [ #  # ]:          0 :                 log_debug("Smack network host rules directory '/etc/smack/netlabel.d/' not found");
     366                 :          0 :                 break;
     367                 :          0 :         case 0:
     368         [ #  # ]:          0 :                 log_info("Successfully loaded Smack network host rules.");
     369                 :          0 :                 break;
     370                 :          0 :         default:
     371         [ #  # ]:          0 :                 log_warning_errno(r, "Failed to load Smack network host rules: %m, ignoring.");
     372                 :          0 :                 break;
     373                 :            :         }
     374                 :            : 
     375                 :          0 :         r = write_onlycap_list();
     376   [ #  #  #  # ]:          0 :         switch(r) {
     377                 :          0 :         case -ENOENT:
     378         [ #  # ]:          0 :                 log_debug("Smack is not enabled in the kernel.");
     379                 :          0 :                 break;
     380                 :          0 :         case ENOENT:
     381         [ #  # ]:          0 :                 log_debug("Smack onlycap list file '/etc/smack/onlycap' not found");
     382                 :          0 :                 break;
     383                 :          0 :         case 0:
     384         [ #  # ]:          0 :                 log_info("Successfully wrote Smack onlycap list.");
     385                 :          0 :                 break;
     386                 :          0 :         default:
     387         [ #  # ]:          0 :                 log_emergency_errno(r, "Failed to write Smack onlycap list: %m");
     388                 :          0 :                 return r;
     389                 :            :         }
     390                 :            : 
     391                 :          0 :         *loaded_policy = true;
     392                 :            : 
     393                 :            : #endif
     394                 :            : 
     395                 :          0 :         return 0;
     396                 :            : }

Generated by: LCOV version 1.14