LCOV - code coverage report
Current view: top level - analyze - analyze-security.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 653 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 29 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <sched.h>
       4             : #include <sys/utsname.h>
       5             : 
       6             : #include "analyze-security.h"
       7             : #include "bus-error.h"
       8             : #include "bus-unit-util.h"
       9             : #include "bus-util.h"
      10             : #include "env-util.h"
      11             : #include "format-table.h"
      12             : #include "in-addr-util.h"
      13             : #include "locale-util.h"
      14             : #include "macro.h"
      15             : #include "missing.h"
      16             : #include "nulstr-util.h"
      17             : #include "parse-util.h"
      18             : #include "path-util.h"
      19             : #include "pretty-print.h"
      20             : #if HAVE_SECCOMP
      21             : #  include "seccomp-util.h"
      22             : #endif
      23             : #include "set.h"
      24             : #include "stdio-util.h"
      25             : #include "strv.h"
      26             : #include "terminal-util.h"
      27             : #include "unit-def.h"
      28             : #include "unit-name.h"
      29             : 
      30             : struct security_info {
      31             :         char *id;
      32             :         char *type;
      33             :         char *load_state;
      34             :         char *fragment_path;
      35             :         bool default_dependencies;
      36             : 
      37             :         uint64_t ambient_capabilities;
      38             :         uint64_t capability_bounding_set;
      39             : 
      40             :         char *user;
      41             :         char **supplementary_groups;
      42             :         bool dynamic_user;
      43             : 
      44             :         bool ip_address_deny_all;
      45             :         bool ip_address_allow_localhost;
      46             :         bool ip_address_allow_other;
      47             : 
      48             :         bool ip_filters_custom_ingress;
      49             :         bool ip_filters_custom_egress;
      50             : 
      51             :         char *keyring_mode;
      52             :         bool lock_personality;
      53             :         bool memory_deny_write_execute;
      54             :         bool no_new_privileges;
      55             :         char *notify_access;
      56             :         bool protect_hostname;
      57             : 
      58             :         bool private_devices;
      59             :         bool private_mounts;
      60             :         bool private_network;
      61             :         bool private_tmp;
      62             :         bool private_users;
      63             : 
      64             :         bool protect_control_groups;
      65             :         bool protect_kernel_modules;
      66             :         bool protect_kernel_tunables;
      67             : 
      68             :         char *protect_home;
      69             :         char *protect_system;
      70             : 
      71             :         bool remove_ipc;
      72             : 
      73             :         bool restrict_address_family_inet;
      74             :         bool restrict_address_family_unix;
      75             :         bool restrict_address_family_netlink;
      76             :         bool restrict_address_family_packet;
      77             :         bool restrict_address_family_other;
      78             : 
      79             :         uint64_t restrict_namespaces;
      80             :         bool restrict_realtime;
      81             :         bool restrict_suid_sgid;
      82             : 
      83             :         char *root_directory;
      84             :         char *root_image;
      85             : 
      86             :         bool delegate;
      87             :         char *device_policy;
      88             :         bool device_allow_non_empty;
      89             : 
      90             :         char **system_call_architectures;
      91             : 
      92             :         bool system_call_filter_whitelist;
      93             :         Set *system_call_filter;
      94             : 
      95             :         uint32_t _umask;
      96             : };
      97             : 
      98             : struct security_assessor {
      99             :         const char *id;
     100             :         const char *description_good;
     101             :         const char *description_bad;
     102             :         const char *description_na;
     103             :         const char *url;
     104             :         uint64_t weight;
     105             :         uint64_t range;
     106             :         int (*assess)(
     107             :                 const struct security_assessor *a,
     108             :                 const struct security_info *info,
     109             :                 const void *data,
     110             :                 uint64_t *ret_badness,
     111             :                 char **ret_description);
     112             :         size_t offset;
     113             :         uint64_t parameter;
     114             :         bool default_dependencies_only;
     115             : };
     116             : 
     117           0 : static void security_info_free(struct security_info *i) {
     118           0 :         if (!i)
     119           0 :                 return;
     120             : 
     121           0 :         free(i->id);
     122           0 :         free(i->type);
     123           0 :         free(i->load_state);
     124           0 :         free(i->fragment_path);
     125             : 
     126           0 :         free(i->user);
     127             : 
     128           0 :         free(i->protect_home);
     129           0 :         free(i->protect_system);
     130             : 
     131           0 :         free(i->root_directory);
     132           0 :         free(i->root_image);
     133             : 
     134           0 :         free(i->keyring_mode);
     135           0 :         free(i->notify_access);
     136             : 
     137           0 :         free(i->device_policy);
     138             : 
     139           0 :         strv_free(i->supplementary_groups);
     140           0 :         strv_free(i->system_call_architectures);
     141             : 
     142           0 :         set_free_free(i->system_call_filter);
     143             : }
     144             : 
     145           0 : static bool security_info_runs_privileged(const struct security_info *i)  {
     146           0 :         assert(i);
     147             : 
     148           0 :         if (STRPTR_IN_SET(i->user, "0", "root"))
     149           0 :                 return true;
     150             : 
     151           0 :         if (i->dynamic_user)
     152           0 :                 return false;
     153             : 
     154           0 :         return isempty(i->user);
     155             : }
     156             : 
     157           0 : static int assess_bool(
     158             :                 const struct security_assessor *a,
     159             :                 const struct security_info *info,
     160             :                 const void *data,
     161             :                 uint64_t *ret_badness,
     162             :                 char **ret_description) {
     163             : 
     164           0 :         const bool *b = data;
     165             : 
     166           0 :         assert(b);
     167           0 :         assert(ret_badness);
     168           0 :         assert(ret_description);
     169             : 
     170           0 :         *ret_badness = a->parameter ? *b : !*b;
     171           0 :         *ret_description = NULL;
     172             : 
     173           0 :         return 0;
     174             : }
     175             : 
     176           0 : static int assess_user(
     177             :                 const struct security_assessor *a,
     178             :                 const struct security_info *info,
     179             :                 const void *data,
     180             :                 uint64_t *ret_badness,
     181             :                 char **ret_description) {
     182             : 
     183           0 :         _cleanup_free_ char *d = NULL;
     184             :         uint64_t b;
     185             : 
     186           0 :         assert(ret_badness);
     187           0 :         assert(ret_description);
     188             : 
     189           0 :         if (streq_ptr(info->user, NOBODY_USER_NAME)) {
     190           0 :                 d = strdup("Service runs under as '" NOBODY_USER_NAME "' user, which should not be used for services");
     191           0 :                 b = 9;
     192           0 :         } else if (info->dynamic_user && !STR_IN_SET(info->user, "0", "root")) {
     193           0 :                 d = strdup("Service runs under a transient non-root user identity");
     194           0 :                 b = 0;
     195           0 :         } else if (info->user && !STR_IN_SET(info->user, "0", "root", "")) {
     196           0 :                 d = strdup("Service runs under a static non-root user identity");
     197           0 :                 b = 0;
     198             :         } else {
     199           0 :                 *ret_badness = 10;
     200           0 :                 *ret_description = NULL;
     201           0 :                 return 0;
     202             :         }
     203             : 
     204           0 :         if (!d)
     205           0 :                 return log_oom();
     206             : 
     207           0 :         *ret_badness = b;
     208           0 :         *ret_description = TAKE_PTR(d);
     209             : 
     210           0 :         return 0;
     211             : }
     212             : 
     213           0 : static int assess_protect_home(
     214             :                 const struct security_assessor *a,
     215             :                 const struct security_info *info,
     216             :                 const void *data,
     217             :                 uint64_t *ret_badness,
     218             :                 char **ret_description) {
     219             : 
     220             :         const char *description;
     221             :         uint64_t badness;
     222             :         char *copy;
     223             :         int r;
     224             : 
     225           0 :         assert(ret_badness);
     226           0 :         assert(ret_description);
     227             : 
     228           0 :         badness = 10;
     229           0 :         description = "Service has full access to home directories";
     230             : 
     231           0 :         r = parse_boolean(info->protect_home);
     232           0 :         if (r < 0) {
     233           0 :                 if (streq_ptr(info->protect_home, "read-only")) {
     234           0 :                         badness = 5;
     235           0 :                         description = "Service has read-only access to home directories";
     236           0 :                 } else if (streq_ptr(info->protect_home, "tmpfs")) {
     237           0 :                         badness = 1;
     238           0 :                         description = "Service has access to fake empty home directories";
     239             :                 }
     240           0 :         } else if (r > 0) {
     241           0 :                 badness = 0;
     242           0 :                 description = "Service has no access to home directories";
     243             :         }
     244             : 
     245           0 :         copy = strdup(description);
     246           0 :         if (!copy)
     247           0 :                 return log_oom();
     248             : 
     249           0 :         *ret_badness = badness;
     250           0 :         *ret_description = copy;
     251             : 
     252           0 :         return 0;
     253             : }
     254             : 
     255           0 : static int assess_protect_system(
     256             :                 const struct security_assessor *a,
     257             :                 const struct security_info *info,
     258             :                 const void *data,
     259             :                 uint64_t *ret_badness,
     260             :                 char **ret_description) {
     261             : 
     262             :         const char *description;
     263             :         uint64_t badness;
     264             :         char *copy;
     265             :         int r;
     266             : 
     267           0 :         assert(ret_badness);
     268           0 :         assert(ret_description);
     269             : 
     270           0 :         badness = 10;
     271           0 :         description = "Service has full access to the OS file hierarchy";
     272             : 
     273           0 :         r = parse_boolean(info->protect_system);
     274           0 :         if (r < 0) {
     275           0 :                 if (streq_ptr(info->protect_system, "full")) {
     276           0 :                         badness = 3;
     277           0 :                         description = "Service has very limited write access to the OS file hierarchy";
     278           0 :                 } else if (streq_ptr(info->protect_system, "strict")) {
     279           0 :                         badness = 0;
     280           0 :                         description = "Service has strict read-only access to the OS file hierarchy";
     281             :                 }
     282           0 :         } else if (r > 0) {
     283           0 :                 badness = 5;
     284           0 :                 description = "Service has limited write access to the OS file hierarchy";
     285             :         }
     286             : 
     287           0 :         copy = strdup(description);
     288           0 :         if (!copy)
     289           0 :                 return log_oom();
     290             : 
     291           0 :         *ret_badness = badness;
     292           0 :         *ret_description = copy;
     293             : 
     294           0 :         return 0;
     295             : }
     296             : 
     297           0 : static int assess_root_directory(
     298             :                 const struct security_assessor *a,
     299             :                 const struct security_info *info,
     300             :                 const void *data,
     301             :                 uint64_t *ret_badness,
     302             :                 char **ret_description) {
     303             : 
     304           0 :         assert(ret_badness);
     305           0 :         assert(ret_description);
     306             : 
     307           0 :         *ret_badness =
     308           0 :                 empty_or_root(info->root_directory) ||
     309           0 :                 empty_or_root(info->root_image);
     310           0 :         *ret_description = NULL;
     311             : 
     312           0 :         return 0;
     313             : }
     314             : 
     315           0 : static int assess_capability_bounding_set(
     316             :                 const struct security_assessor *a,
     317             :                 const struct security_info *info,
     318             :                 const void *data,
     319             :                 uint64_t *ret_badness,
     320             :                 char **ret_description) {
     321             : 
     322           0 :         assert(ret_badness);
     323           0 :         assert(ret_description);
     324             : 
     325           0 :         *ret_badness = !!(info->capability_bounding_set & a->parameter);
     326           0 :         *ret_description = NULL;
     327             : 
     328           0 :         return 0;
     329             : }
     330             : 
     331           0 : static int assess_umask(
     332             :                 const struct security_assessor *a,
     333             :                 const struct security_info *info,
     334             :                 const void *data,
     335             :                 uint64_t *ret_badness,
     336             :                 char **ret_description) {
     337             : 
     338           0 :         char *copy = NULL;
     339             :         const char *d;
     340             :         uint64_t b;
     341             : 
     342           0 :         assert(ret_badness);
     343           0 :         assert(ret_description);
     344             : 
     345           0 :         if (!FLAGS_SET(info->_umask, 0002)) {
     346           0 :                 d = "Files created by service are world-writable by default";
     347           0 :                 b = 10;
     348           0 :         } else if (!FLAGS_SET(info->_umask, 0004)) {
     349           0 :                 d = "Files created by service are world-readable by default";
     350           0 :                 b = 5;
     351           0 :         } else if (!FLAGS_SET(info->_umask, 0020)) {
     352           0 :                 d = "Files created by service are group-writable by default";
     353           0 :                 b = 2;
     354           0 :         } else if (!FLAGS_SET(info->_umask, 0040)) {
     355           0 :                 d = "Files created by service are group-readable by default";
     356           0 :                 b = 1;
     357             :         } else {
     358           0 :                 d = "Files created by service are accessible only by service's own user by default";
     359           0 :                 b = 0;
     360             :         }
     361             : 
     362           0 :         copy = strdup(d);
     363           0 :         if (!copy)
     364           0 :                 return log_oom();
     365             : 
     366           0 :         *ret_badness = b;
     367           0 :         *ret_description = copy;
     368             : 
     369           0 :         return 0;
     370             : }
     371             : 
     372           0 : static int assess_keyring_mode(
     373             :                 const struct security_assessor *a,
     374             :                 const struct security_info *info,
     375             :                 const void *data,
     376             :                 uint64_t *ret_badness,
     377             :                 char **ret_description) {
     378             : 
     379           0 :         assert(ret_badness);
     380           0 :         assert(ret_description);
     381             : 
     382           0 :         *ret_badness = !streq_ptr(info->keyring_mode, "private");
     383           0 :         *ret_description = NULL;
     384             : 
     385           0 :         return 0;
     386             : }
     387             : 
     388           0 : static int assess_notify_access(
     389             :                 const struct security_assessor *a,
     390             :                 const struct security_info *info,
     391             :                 const void *data,
     392             :                 uint64_t *ret_badness,
     393             :                 char **ret_description) {
     394             : 
     395           0 :         assert(ret_badness);
     396           0 :         assert(ret_description);
     397             : 
     398           0 :         *ret_badness = streq_ptr(info->notify_access, "all");
     399           0 :         *ret_description = NULL;
     400             : 
     401           0 :         return 0;
     402             : }
     403             : 
     404           0 : static int assess_remove_ipc(
     405             :                 const struct security_assessor *a,
     406             :                 const struct security_info *info,
     407             :                 const void *data,
     408             :                 uint64_t *ret_badness,
     409             :                 char **ret_description) {
     410             : 
     411           0 :         assert(ret_badness);
     412           0 :         assert(ret_description);
     413             : 
     414           0 :         if (security_info_runs_privileged(info))
     415           0 :                 *ret_badness = UINT64_MAX;
     416             :         else
     417           0 :                 *ret_badness = !info->remove_ipc;
     418             : 
     419           0 :         *ret_description = NULL;
     420           0 :         return 0;
     421             : }
     422             : 
     423           0 : static int assess_supplementary_groups(
     424             :                 const struct security_assessor *a,
     425             :                 const struct security_info *info,
     426             :                 const void *data,
     427             :                 uint64_t *ret_badness,
     428             :                 char **ret_description) {
     429             : 
     430           0 :         assert(ret_badness);
     431           0 :         assert(ret_description);
     432             : 
     433           0 :         if (security_info_runs_privileged(info))
     434           0 :                 *ret_badness = UINT64_MAX;
     435             :         else
     436           0 :                 *ret_badness = !strv_isempty(info->supplementary_groups);
     437             : 
     438           0 :         *ret_description = NULL;
     439           0 :         return 0;
     440             : }
     441             : 
     442           0 : static int assess_restrict_namespaces(
     443             :                 const struct security_assessor *a,
     444             :                 const struct security_info *info,
     445             :                 const void *data,
     446             :                 uint64_t *ret_badness,
     447             :                 char **ret_description) {
     448             : 
     449           0 :         assert(ret_badness);
     450           0 :         assert(ret_description);
     451             : 
     452           0 :         *ret_badness = !!(info->restrict_namespaces & a->parameter);
     453           0 :         *ret_description = NULL;
     454             : 
     455           0 :         return 0;
     456             : }
     457             : 
     458           0 : static int assess_system_call_architectures(
     459             :                 const struct security_assessor *a,
     460             :                 const struct security_info *info,
     461             :                 const void *data,
     462             :                 uint64_t *ret_badness,
     463             :                 char **ret_description) {
     464             : 
     465             :         char *d;
     466             :         uint64_t b;
     467             : 
     468           0 :         assert(ret_badness);
     469           0 :         assert(ret_description);
     470             : 
     471           0 :         if (strv_isempty(info->system_call_architectures)) {
     472           0 :                 b = 10;
     473           0 :                 d = strdup("Service may execute system calls with all ABIs");
     474           0 :         } else if (strv_equal(info->system_call_architectures, STRV_MAKE("native"))) {
     475           0 :                 b = 0;
     476           0 :                 d = strdup("Service may execute system calls only with native ABI");
     477             :         } else {
     478           0 :                 b = 8;
     479           0 :                 d = strdup("Service may execute system calls with multiple ABIs");
     480             :         }
     481             : 
     482           0 :         if (!d)
     483           0 :                 return log_oom();
     484             : 
     485           0 :         *ret_badness = b;
     486           0 :         *ret_description = d;
     487             : 
     488           0 :         return 0;
     489             : }
     490             : 
     491             : #if HAVE_SECCOMP
     492             : 
     493           0 : static bool syscall_names_in_filter(Set *s, bool whitelist, const SyscallFilterSet *f) {
     494             :         const char *syscall;
     495             : 
     496           0 :         NULSTR_FOREACH(syscall, f->value) {
     497             :                 int id;
     498             : 
     499           0 :                 if (syscall[0] == '@') {
     500             :                         const SyscallFilterSet *g;
     501             : 
     502           0 :                         assert_se(g = syscall_filter_set_find(syscall));
     503           0 :                         if (syscall_names_in_filter(s, whitelist, g))
     504           0 :                                 return true; /* bad! */
     505             : 
     506           0 :                         continue;
     507             :                 }
     508             : 
     509             :                 /* Let's see if the system call actually exists on this platform, before complaining */
     510           0 :                 id = seccomp_syscall_resolve_name(syscall);
     511           0 :                 if (id < 0)
     512           0 :                         continue;
     513             : 
     514           0 :                 if (set_contains(s, syscall) == whitelist) {
     515           0 :                         log_debug("Offending syscall filter item: %s", syscall);
     516           0 :                         return true; /* bad! */
     517             :                 }
     518             :         }
     519             : 
     520           0 :         return false;
     521             : }
     522             : 
     523           0 : static int assess_system_call_filter(
     524             :                 const struct security_assessor *a,
     525             :                 const struct security_info *info,
     526             :                 const void *data,
     527             :                 uint64_t *ret_badness,
     528             :                 char **ret_description) {
     529             : 
     530             :         const SyscallFilterSet *f;
     531           0 :         char *d = NULL;
     532             :         uint64_t b;
     533             : 
     534           0 :         assert(a);
     535           0 :         assert(info);
     536           0 :         assert(ret_badness);
     537           0 :         assert(ret_description);
     538             : 
     539           0 :         assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
     540           0 :         f = syscall_filter_sets + a->parameter;
     541             : 
     542           0 :         if (!info->system_call_filter_whitelist && set_isempty(info->system_call_filter)) {
     543           0 :                 d = strdup("Service does not filter system calls");
     544           0 :                 b = 10;
     545             :         } else {
     546             :                 bool bad;
     547             : 
     548           0 :                 log_debug("Analyzing system call filter, checking against: %s", f->name);
     549           0 :                 bad = syscall_names_in_filter(info->system_call_filter, info->system_call_filter_whitelist, f);
     550           0 :                 log_debug("Result: %s", bad ? "bad" : "good");
     551             : 
     552           0 :                 if (info->system_call_filter_whitelist) {
     553           0 :                         if (bad) {
     554           0 :                                 (void) asprintf(&d, "System call whitelist defined for service, and %s is included", f->name);
     555           0 :                                 b = 9;
     556             :                         } else {
     557           0 :                                 (void) asprintf(&d, "System call whitelist defined for service, and %s is not included", f->name);
     558           0 :                                 b = 0;
     559             :                         }
     560             :                 } else {
     561           0 :                         if (bad) {
     562           0 :                                 (void) asprintf(&d, "System call blacklist defined for service, and %s is not included", f->name);
     563           0 :                                 b = 10;
     564             :                         } else {
     565           0 :                                 (void) asprintf(&d, "System call blacklist defined for service, and %s is included", f->name);
     566           0 :                                 b = 5;
     567             :                         }
     568             :                 }
     569             :         }
     570             : 
     571           0 :         if (!d)
     572           0 :                 return log_oom();
     573             : 
     574           0 :         *ret_badness = b;
     575           0 :         *ret_description = d;
     576             : 
     577           0 :         return 0;
     578             : }
     579             : 
     580             : #endif
     581             : 
     582           0 : static int assess_ip_address_allow(
     583             :                 const struct security_assessor *a,
     584             :                 const struct security_info *info,
     585             :                 const void *data,
     586             :                 uint64_t *ret_badness,
     587             :                 char **ret_description) {
     588             : 
     589           0 :         char *d = NULL;
     590             :         uint64_t b;
     591             : 
     592           0 :         assert(info);
     593           0 :         assert(ret_badness);
     594           0 :         assert(ret_description);
     595             : 
     596           0 :         if (info->ip_filters_custom_ingress || info->ip_filters_custom_egress) {
     597           0 :                 d = strdup("Service defines custom ingress/egress IP filters with BPF programs");
     598           0 :                 b = 0;
     599           0 :         } else if (!info->ip_address_deny_all) {
     600           0 :                 d = strdup("Service does not define an IP address whitelist");
     601           0 :                 b = 10;
     602           0 :         } else if (info->ip_address_allow_other) {
     603           0 :                 d = strdup("Service defines IP address whitelist with non-localhost entries");
     604           0 :                 b = 5;
     605           0 :         } else if (info->ip_address_allow_localhost) {
     606           0 :                 d = strdup("Service defines IP address whitelist with only localhost entries");
     607           0 :                 b = 2;
     608             :         } else {
     609           0 :                 d = strdup("Service blocks all IP address ranges");
     610           0 :                 b = 0;
     611             :         }
     612             : 
     613           0 :         if (!d)
     614           0 :                 return log_oom();
     615             : 
     616           0 :         *ret_badness = b;
     617           0 :         *ret_description = d;
     618             : 
     619           0 :         return 0;
     620             : }
     621             : 
     622           0 : static int assess_device_allow(
     623             :                 const struct security_assessor *a,
     624             :                 const struct security_info *info,
     625             :                 const void *data,
     626             :                 uint64_t *ret_badness,
     627             :                 char **ret_description) {
     628             : 
     629           0 :         char *d = NULL;
     630             :         uint64_t b;
     631             : 
     632           0 :         assert(info);
     633           0 :         assert(ret_badness);
     634           0 :         assert(ret_description);
     635             : 
     636           0 :         if (STRPTR_IN_SET(info->device_policy, "strict", "closed")) {
     637             : 
     638           0 :                 if (info->device_allow_non_empty) {
     639           0 :                         d = strdup("Service has a device ACL with some special devices");
     640           0 :                         b = 5;
     641             :                 } else {
     642           0 :                         d = strdup("Service has a minimal device ACL");
     643           0 :                         b = 0;
     644             :                 }
     645             :         } else {
     646           0 :                 d = strdup("Service has no device ACL");
     647           0 :                 b = 10;
     648             :         }
     649             : 
     650           0 :         if (!d)
     651           0 :                 return log_oom();
     652             : 
     653           0 :         *ret_badness = b;
     654           0 :         *ret_description = d;
     655             : 
     656           0 :         return 0;
     657             : }
     658             : 
     659           0 : static int assess_ambient_capabilities(
     660             :                 const struct security_assessor *a,
     661             :                 const struct security_info *info,
     662             :                 const void *data,
     663             :                 uint64_t *ret_badness,
     664             :                 char **ret_description) {
     665             : 
     666           0 :         assert(ret_badness);
     667           0 :         assert(ret_description);
     668             : 
     669           0 :         *ret_badness = info->ambient_capabilities != 0;
     670           0 :         *ret_description = NULL;
     671             : 
     672           0 :         return 0;
     673             : }
     674             : 
     675             : static const struct security_assessor security_assessor_table[] = {
     676             :         {
     677             :                 .id = "User=/DynamicUser=",
     678             :                 .description_bad = "Service runs as root user",
     679             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#User=",
     680             :                 .weight = 2000,
     681             :                 .range = 10,
     682             :                 .assess = assess_user,
     683             :         },
     684             :         {
     685             :                 .id = "SupplementaryGroups=",
     686             :                 .description_good = "Service has no supplementary groups",
     687             :                 .description_bad = "Service runs with supplementary groups",
     688             :                 .description_na = "Service runs as root, option does not matter",
     689             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SupplementaryGroups=",
     690             :                 .weight = 200,
     691             :                 .range = 1,
     692             :                 .assess = assess_supplementary_groups,
     693             :         },
     694             :         {
     695             :                 .id = "PrivateDevices=",
     696             :                 .description_good = "Service has no access to hardware devices",
     697             :                 .description_bad = "Service potentially has access to hardware devices",
     698             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateDevices=",
     699             :                 .weight = 1000,
     700             :                 .range = 1,
     701             :                 .assess = assess_bool,
     702             :                 .offset = offsetof(struct security_info, private_devices),
     703             :         },
     704             :         {
     705             :                 .id = "PrivateMounts=",
     706             :                 .description_good = "Service cannot install system mounts",
     707             :                 .description_bad = "Service may install system mounts",
     708             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateMounts=",
     709             :                 .weight = 1000,
     710             :                 .range = 1,
     711             :                 .assess = assess_bool,
     712             :                 .offset = offsetof(struct security_info, private_mounts),
     713             :         },
     714             :         {
     715             :                 .id = "PrivateNetwork=",
     716             :                 .description_good = "Service has no access to the host's network",
     717             :                 .description_bad = "Service has access to the host's network",
     718             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateNetwork=",
     719             :                 .weight = 2500,
     720             :                 .range = 1,
     721             :                 .assess = assess_bool,
     722             :                 .offset = offsetof(struct security_info, private_network),
     723             :         },
     724             :         {
     725             :                 .id = "PrivateTmp=",
     726             :                 .description_good = "Service has no access to other software's temporary files",
     727             :                 .description_bad = "Service has access to other software's temporary files",
     728             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateTmp=",
     729             :                 .weight = 1000,
     730             :                 .range = 1,
     731             :                 .assess = assess_bool,
     732             :                 .offset = offsetof(struct security_info, private_tmp),
     733             :                 .default_dependencies_only = true,
     734             :         },
     735             :         {
     736             :                 .id = "PrivateUsers=",
     737             :                 .description_good = "Service does not have access to other users",
     738             :                 .description_bad = "Service has access to other users",
     739             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateUsers=",
     740             :                 .weight = 1000,
     741             :                 .range = 1,
     742             :                 .assess = assess_bool,
     743             :                 .offset = offsetof(struct security_info, private_users),
     744             :         },
     745             :         {
     746             :                 .id = "ProtectControlGroups=",
     747             :                 .description_good = "Service cannot modify the control group file system",
     748             :                 .description_bad = "Service may modify to the control group file system",
     749             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectControlGroups=",
     750             :                 .weight = 1000,
     751             :                 .range = 1,
     752             :                 .assess = assess_bool,
     753             :                 .offset = offsetof(struct security_info, protect_control_groups),
     754             :         },
     755             :         {
     756             :                 .id = "ProtectKernelModules=",
     757             :                 .description_good = "Service cannot load or read kernel modules",
     758             :                 .description_bad = "Service may load or read kernel modules",
     759             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectKernelModules=",
     760             :                 .weight = 1000,
     761             :                 .range = 1,
     762             :                 .assess = assess_bool,
     763             :                 .offset = offsetof(struct security_info, protect_kernel_modules),
     764             :         },
     765             :         {
     766             :                 .id = "ProtectKernelTunables=",
     767             :                 .description_good = "Service cannot alter kernel tunables (/proc/sys, …)",
     768             :                 .description_bad = "Service may alter kernel tunables",
     769             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectKernelTunables=",
     770             :                 .weight = 1000,
     771             :                 .range = 1,
     772             :                 .assess = assess_bool,
     773             :                 .offset = offsetof(struct security_info, protect_kernel_tunables),
     774             :         },
     775             :         {
     776             :                 .id = "ProtectHome=",
     777             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHome=",
     778             :                 .weight = 1000,
     779             :                 .range = 10,
     780             :                 .assess = assess_protect_home,
     781             :                 .default_dependencies_only = true,
     782             :         },
     783             :         {
     784             :                 .id = "ProtectHostname=",
     785             :                 .description_good = "Service cannot change system host/domainname",
     786             :                 .description_bad = "Service may change system host/domainname",
     787             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHostname=",
     788             :                 .weight = 50,
     789             :                 .range = 1,
     790             :                 .assess = assess_bool,
     791             :                 .offset = offsetof(struct security_info, protect_hostname),
     792             :         },
     793             :         {
     794             :                 .id = "ProtectSystem=",
     795             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectSystem=",
     796             :                 .weight = 1000,
     797             :                 .range = 10,
     798             :                 .assess = assess_protect_system,
     799             :                 .default_dependencies_only = true,
     800             :         },
     801             :         {
     802             :                 .id = "RootDirectory=/RootImage=",
     803             :                 .description_good = "Service has its own root directory/image",
     804             :                 .description_bad = "Service runs within the host's root directory",
     805             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RootDirectory=",
     806             :                 .weight = 200,
     807             :                 .range = 1,
     808             :                 .assess = assess_root_directory,
     809             :                 .default_dependencies_only = true,
     810             :         },
     811             :         {
     812             :                 .id = "LockPersonality=",
     813             :                 .description_good = "Service cannot change ABI personality",
     814             :                 .description_bad = "Service may change ABI personality",
     815             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#LockPersonality=",
     816             :                 .weight = 100,
     817             :                 .range = 1,
     818             :                 .assess = assess_bool,
     819             :                 .offset = offsetof(struct security_info, lock_personality),
     820             :         },
     821             :         {
     822             :                 .id = "MemoryDenyWriteExecute=",
     823             :                 .description_good = "Service cannot create writable executable memory mappings",
     824             :                 .description_bad = "Service may create writable executable memory mappings",
     825             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#MemoryDenyWriteExecute=",
     826             :                 .weight = 100,
     827             :                 .range = 1,
     828             :                 .assess = assess_bool,
     829             :                 .offset = offsetof(struct security_info, memory_deny_write_execute),
     830             :         },
     831             :         {
     832             :                 .id = "NoNewPrivileges=",
     833             :                 .description_good = "Service processes cannot acquire new privileges",
     834             :                 .description_bad = "Service processes may acquire new privileges",
     835             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#NoNewPrivileges=",
     836             :                 .weight = 1000,
     837             :                 .range = 1,
     838             :                 .assess = assess_bool,
     839             :                 .offset = offsetof(struct security_info, no_new_privileges),
     840             :         },
     841             :         {
     842             :                 .id = "CapabilityBoundingSet=~CAP_SYS_ADMIN",
     843             :                 .description_good = "Service has no administrator privileges",
     844             :                 .description_bad = "Service has administrator privileges",
     845             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     846             :                 .weight = 1500,
     847             :                 .range = 1,
     848             :                 .assess = assess_capability_bounding_set,
     849             :                 .parameter = UINT64_C(1) << CAP_SYS_ADMIN,
     850             :         },
     851             :         {
     852             :                 .id = "CapabilityBoundingSet=~CAP_SET(UID|GID|PCAP)",
     853             :                 .description_good = "Service cannot change UID/GID identities/capabilities",
     854             :                 .description_bad = "Service may change UID/GID identities/capabilities",
     855             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     856             :                 .weight = 1500,
     857             :                 .range = 1,
     858             :                 .assess = assess_capability_bounding_set,
     859             :                 .parameter = (UINT64_C(1) << CAP_SETUID)|
     860             :                              (UINT64_C(1) << CAP_SETGID)|
     861             :                              (UINT64_C(1) << CAP_SETPCAP),
     862             :         },
     863             :         {
     864             :                 .id = "CapabilityBoundingSet=~CAP_SYS_PTRACE",
     865             :                 .description_good = "Service has no ptrace() debugging abilities",
     866             :                 .description_bad = "Service has ptrace() debugging abilities",
     867             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     868             :                 .weight = 1500,
     869             :                 .range = 1,
     870             :                 .assess = assess_capability_bounding_set,
     871             :                 .parameter = (UINT64_C(1) << CAP_SYS_PTRACE),
     872             :         },
     873             :         {
     874             :                 .id = "CapabilityBoundingSet=~CAP_SYS_TIME",
     875             :                 .description_good = "Service processes cannot change the system clock",
     876             :                 .description_bad = "Service processes may change the system clock",
     877             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     878             :                 .weight = 1000,
     879             :                 .range = 1,
     880             :                 .assess = assess_capability_bounding_set,
     881             :                 .parameter = UINT64_C(1) << CAP_SYS_TIME,
     882             :         },
     883             :         {
     884             :                 .id = "CapabilityBoundingSet=~CAP_NET_ADMIN",
     885             :                 .description_good = "Service has no network configuration privileges",
     886             :                 .description_bad = "Service has network configuration privileges",
     887             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     888             :                 .weight = 1000,
     889             :                 .range = 1,
     890             :                 .assess = assess_capability_bounding_set,
     891             :                 .parameter = (UINT64_C(1) << CAP_NET_ADMIN),
     892             :         },
     893             :         {
     894             :                 .id = "CapabilityBoundingSet=~CAP_RAWIO",
     895             :                 .description_good = "Service has no raw I/O access",
     896             :                 .description_bad = "Service has raw I/O access",
     897             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     898             :                 .weight = 1000,
     899             :                 .range = 1,
     900             :                 .assess = assess_capability_bounding_set,
     901             :                 .parameter = (UINT64_C(1) << CAP_SYS_RAWIO),
     902             :         },
     903             :         {
     904             :                 .id = "CapabilityBoundingSet=~CAP_SYS_MODULE",
     905             :                 .description_good = "Service cannot load kernel modules",
     906             :                 .description_bad = "Service may load kernel modules",
     907             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     908             :                 .weight = 1000,
     909             :                 .range = 1,
     910             :                 .assess = assess_capability_bounding_set,
     911             :                 .parameter = (UINT64_C(1) << CAP_SYS_MODULE),
     912             :         },
     913             :         {
     914             :                 .id = "CapabilityBoundingSet=~CAP_AUDIT_*",
     915             :                 .description_good = "Service has no audit subsystem access",
     916             :                 .description_bad = "Service has audit subsystem access",
     917             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     918             :                 .weight = 500,
     919             :                 .range = 1,
     920             :                 .assess = assess_capability_bounding_set,
     921             :                 .parameter = (UINT64_C(1) << CAP_AUDIT_CONTROL) |
     922             :                              (UINT64_C(1) << CAP_AUDIT_READ) |
     923             :                              (UINT64_C(1) << CAP_AUDIT_WRITE),
     924             :         },
     925             :         {
     926             :                 .id = "CapabilityBoundingSet=~CAP_SYSLOG",
     927             :                 .description_good = "Service has no access to kernel logging",
     928             :                 .description_bad = "Service has access to kernel logging",
     929             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     930             :                 .weight = 500,
     931             :                 .range = 1,
     932             :                 .assess = assess_capability_bounding_set,
     933             :                 .parameter = (UINT64_C(1) << CAP_SYSLOG),
     934             :         },
     935             :         {
     936             :                 .id = "CapabilityBoundingSet=~CAP_SYS_(NICE|RESOURCE)",
     937             :                 .description_good = "Service has no privileges to change resource use parameters",
     938             :                 .description_bad = "Service has privileges to change resource use parameters",
     939             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     940             :                 .weight = 500,
     941             :                 .range = 1,
     942             :                 .assess = assess_capability_bounding_set,
     943             :                 .parameter = (UINT64_C(1) << CAP_SYS_NICE) |
     944             :                              (UINT64_C(1) << CAP_SYS_RESOURCE),
     945             :         },
     946             :         {
     947             :                 .id = "CapabilityBoundingSet=~CAP_MKNOD",
     948             :                 .description_good = "Service cannot create device nodes",
     949             :                 .description_bad = "Service may create device nodes",
     950             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     951             :                 .weight = 500,
     952             :                 .range = 1,
     953             :                 .assess = assess_capability_bounding_set,
     954             :                 .parameter = (UINT64_C(1) << CAP_MKNOD),
     955             :         },
     956             :         {
     957             :                 .id = "CapabilityBoundingSet=~CAP_(CHOWN|FSETID|SETFCAP)",
     958             :                 .description_good = "Service cannot change file ownership/access mode/capabilities",
     959             :                 .description_bad = "Service may change file ownership/access mode/capabilities unrestricted",
     960             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     961             :                 .weight = 1000,
     962             :                 .range = 1,
     963             :                 .assess = assess_capability_bounding_set,
     964             :                 .parameter = (UINT64_C(1) << CAP_CHOWN) |
     965             :                              (UINT64_C(1) << CAP_FSETID) |
     966             :                              (UINT64_C(1) << CAP_SETFCAP),
     967             :         },
     968             :         {
     969             :                 .id = "CapabilityBoundingSet=~CAP_(DAC_*|FOWNER|IPC_OWNER)",
     970             :                 .description_good = "Service cannot override UNIX file/IPC permission checks",
     971             :                 .description_bad = "Service may override UNIX file/IPC permission checks",
     972             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     973             :                 .weight = 1000,
     974             :                 .range = 1,
     975             :                 .assess = assess_capability_bounding_set,
     976             :                 .parameter = (UINT64_C(1) << CAP_DAC_OVERRIDE) |
     977             :                              (UINT64_C(1) << CAP_DAC_READ_SEARCH) |
     978             :                              (UINT64_C(1) << CAP_FOWNER) |
     979             :                              (UINT64_C(1) << CAP_IPC_OWNER),
     980             :         },
     981             :         {
     982             :                 .id = "CapabilityBoundingSet=~CAP_KILL",
     983             :                 .description_good = "Service cannot send UNIX signals to arbitrary processes",
     984             :                 .description_bad = "Service may send UNIX signals to arbitrary processes",
     985             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     986             :                 .weight = 500,
     987             :                 .range = 1,
     988             :                 .assess = assess_capability_bounding_set,
     989             :                 .parameter = (UINT64_C(1) << CAP_KILL),
     990             :         },
     991             :         {
     992             :                 .id = "CapabilityBoundingSet=~CAP_NET_(BIND_SERVICE|BROADCAST|RAW)",
     993             :                 .description_good = "Service has no elevated networking privileges",
     994             :                 .description_bad = "Service has elevated networking privileges",
     995             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
     996             :                 .weight = 500,
     997             :                 .range = 1,
     998             :                 .assess = assess_capability_bounding_set,
     999             :                 .parameter = (UINT64_C(1) << CAP_NET_BIND_SERVICE) |
    1000             :                              (UINT64_C(1) << CAP_NET_BROADCAST) |
    1001             :                              (UINT64_C(1) << CAP_NET_RAW),
    1002             :         },
    1003             :         {
    1004             :                 .id = "CapabilityBoundingSet=~CAP_SYS_BOOT",
    1005             :                 .description_good = "Service cannot issue reboot()",
    1006             :                 .description_bad = "Service may issue reboot()",
    1007             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1008             :                 .weight = 100,
    1009             :                 .range = 1,
    1010             :                 .assess = assess_capability_bounding_set,
    1011             :                 .parameter = (UINT64_C(1) << CAP_SYS_BOOT),
    1012             :         },
    1013             :         {
    1014             :                 .id = "CapabilityBoundingSet=~CAP_MAC_*",
    1015             :                 .description_good = "Service cannot adjust SMACK MAC",
    1016             :                 .description_bad = "Service may adjust SMACK MAC",
    1017             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1018             :                 .weight = 100,
    1019             :                 .range = 1,
    1020             :                 .assess = assess_capability_bounding_set,
    1021             :                 .parameter = (UINT64_C(1) << CAP_MAC_ADMIN)|
    1022             :                              (UINT64_C(1) << CAP_MAC_OVERRIDE),
    1023             :         },
    1024             :         {
    1025             :                 .id = "CapabilityBoundingSet=~CAP_LINUX_IMMUTABLE",
    1026             :                 .description_good = "Service cannot mark files immutable",
    1027             :                 .description_bad = "Service may mark files immutable",
    1028             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1029             :                 .weight = 75,
    1030             :                 .range = 1,
    1031             :                 .assess = assess_capability_bounding_set,
    1032             :                 .parameter = (UINT64_C(1) << CAP_LINUX_IMMUTABLE),
    1033             :         },
    1034             :         {
    1035             :                 .id = "CapabilityBoundingSet=~CAP_IPC_LOCK",
    1036             :                 .description_good = "Service cannot lock memory into RAM",
    1037             :                 .description_bad = "Service may lock memory into RAM",
    1038             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1039             :                 .weight = 50,
    1040             :                 .range = 1,
    1041             :                 .assess = assess_capability_bounding_set,
    1042             :                 .parameter = (UINT64_C(1) << CAP_IPC_LOCK),
    1043             :         },
    1044             :         {
    1045             :                 .id = "CapabilityBoundingSet=~CAP_SYS_CHROOT",
    1046             :                 .description_good = "Service cannot issue chroot()",
    1047             :                 .description_bad = "Service may issue chroot()",
    1048             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1049             :                 .weight = 50,
    1050             :                 .range = 1,
    1051             :                 .assess = assess_capability_bounding_set,
    1052             :                 .parameter = (UINT64_C(1) << CAP_SYS_CHROOT),
    1053             :         },
    1054             :         {
    1055             :                 .id = "CapabilityBoundingSet=~CAP_BLOCK_SUSPEND",
    1056             :                 .description_good = "Service cannot establish wake locks",
    1057             :                 .description_bad = "Service may establish wake locks",
    1058             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1059             :                 .weight = 25,
    1060             :                 .range = 1,
    1061             :                 .assess = assess_capability_bounding_set,
    1062             :                 .parameter = (UINT64_C(1) << CAP_BLOCK_SUSPEND),
    1063             :         },
    1064             :         {
    1065             :                 .id = "CapabilityBoundingSet=~CAP_WAKE_ALARM",
    1066             :                 .description_good = "Service cannot program timers that wake up the system",
    1067             :                 .description_bad = "Service may program timers that wake up the system",
    1068             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1069             :                 .weight = 25,
    1070             :                 .range = 1,
    1071             :                 .assess = assess_capability_bounding_set,
    1072             :                 .parameter = (UINT64_C(1) << CAP_WAKE_ALARM),
    1073             :         },
    1074             :         {
    1075             :                 .id = "CapabilityBoundingSet=~CAP_LEASE",
    1076             :                 .description_good = "Service cannot create file leases",
    1077             :                 .description_bad = "Service may create file leases",
    1078             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1079             :                 .weight = 25,
    1080             :                 .range = 1,
    1081             :                 .assess = assess_capability_bounding_set,
    1082             :                 .parameter = (UINT64_C(1) << CAP_LEASE),
    1083             :         },
    1084             :         {
    1085             :                 .id = "CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG",
    1086             :                 .description_good = "Service cannot issue vhangup()",
    1087             :                 .description_bad = "Service may issue vhangup()",
    1088             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1089             :                 .weight = 25,
    1090             :                 .range = 1,
    1091             :                 .assess = assess_capability_bounding_set,
    1092             :                 .parameter = (UINT64_C(1) << CAP_SYS_TTY_CONFIG),
    1093             :         },
    1094             :         {
    1095             :                 .id = "CapabilityBoundingSet=~CAP_SYS_PACCT",
    1096             :                 .description_good = "Service cannot use acct()",
    1097             :                 .description_bad = "Service may use acct()",
    1098             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
    1099             :                 .weight = 25,
    1100             :                 .range = 1,
    1101             :                 .assess = assess_capability_bounding_set,
    1102             :                 .parameter = (UINT64_C(1) << CAP_SYS_PACCT),
    1103             :         },
    1104             :         {
    1105             :                 .id = "UMask=",
    1106             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#UMask=",
    1107             :                 .weight = 100,
    1108             :                 .range = 10,
    1109             :                 .assess = assess_umask,
    1110             :         },
    1111             :         {
    1112             :                 .id = "KeyringMode=",
    1113             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#KeyringMode=",
    1114             :                 .description_good = "Service doesn't share key material with other services",
    1115             :                 .description_bad = "Service shares key material with other service",
    1116             :                 .weight = 1000,
    1117             :                 .range = 1,
    1118             :                 .assess = assess_keyring_mode,
    1119             :         },
    1120             :         {
    1121             :                 .id = "NotifyAccess=",
    1122             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#NotifyAccess=",
    1123             :                 .description_good = "Service child processes cannot alter service state",
    1124             :                 .description_bad = "Service child processes may alter service state",
    1125             :                 .weight = 1000,
    1126             :                 .range = 1,
    1127             :                 .assess = assess_notify_access,
    1128             :         },
    1129             :         {
    1130             :                 .id = "RemoveIPC=",
    1131             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RemoveIPC=",
    1132             :                 .description_good = "Service user cannot leave SysV IPC objects around",
    1133             :                 .description_bad = "Service user may leave SysV IPC objects around",
    1134             :                 .description_na = "Service runs as root, option does not apply",
    1135             :                 .weight = 100,
    1136             :                 .range = 1,
    1137             :                 .assess = assess_remove_ipc,
    1138             :                 .offset = offsetof(struct security_info, remove_ipc),
    1139             :         },
    1140             :         {
    1141             :                 .id = "Delegate=",
    1142             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Delegate=",
    1143             :                 .description_good = "Service does not maintain its own delegated control group subtree",
    1144             :                 .description_bad = "Service maintains its own delegated control group subtree",
    1145             :                 .weight = 100,
    1146             :                 .range = 1,
    1147             :                 .assess = assess_bool,
    1148             :                 .offset = offsetof(struct security_info, delegate),
    1149             :                 .parameter = true, /* invert! */
    1150             :         },
    1151             :         {
    1152             :                 .id = "RestrictRealtime=",
    1153             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictRealtime=",
    1154             :                 .description_good = "Service realtime scheduling access is restricted",
    1155             :                 .description_bad = "Service may acquire realtime scheduling",
    1156             :                 .weight = 500,
    1157             :                 .range = 1,
    1158             :                 .assess = assess_bool,
    1159             :                 .offset = offsetof(struct security_info, restrict_realtime),
    1160             :         },
    1161             :         {
    1162             :                 .id = "RestrictSUIDSGID=",
    1163             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictSUIDSGID=",
    1164             :                 .description_good = "SUID/SGID file creation by service is restricted",
    1165             :                 .description_bad = "Service may create SUID/SGID files",
    1166             :                 .weight = 1000,
    1167             :                 .range = 1,
    1168             :                 .assess = assess_bool,
    1169             :                 .offset = offsetof(struct security_info, restrict_suid_sgid),
    1170             :         },
    1171             :         {
    1172             :                 .id = "RestrictNamespaces=~CLONE_NEWUSER",
    1173             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
    1174             :                 .description_good = "Service cannot create user namespaces",
    1175             :                 .description_bad = "Service may create user namespaces",
    1176             :                 .weight = 1500,
    1177             :                 .range = 1,
    1178             :                 .assess = assess_restrict_namespaces,
    1179             :                 .parameter = CLONE_NEWUSER,
    1180             :         },
    1181             :         {
    1182             :                 .id = "RestrictNamespaces=~CLONE_NEWNS",
    1183             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
    1184             :                 .description_good = "Service cannot create file system namespaces",
    1185             :                 .description_bad = "Service may create file system namespaces",
    1186             :                 .weight = 500,
    1187             :                 .range = 1,
    1188             :                 .assess = assess_restrict_namespaces,
    1189             :                 .parameter = CLONE_NEWNS,
    1190             :         },
    1191             :         {
    1192             :                 .id = "RestrictNamespaces=~CLONE_NEWIPC",
    1193             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
    1194             :                 .description_good = "Service cannot create IPC namespaces",
    1195             :                 .description_bad = "Service may create IPC namespaces",
    1196             :                 .weight = 500,
    1197             :                 .range = 1,
    1198             :                 .assess = assess_restrict_namespaces,
    1199             :                 .parameter = CLONE_NEWIPC,
    1200             :         },
    1201             :         {
    1202             :                 .id = "RestrictNamespaces=~CLONE_NEWPID",
    1203             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
    1204             :                 .description_good = "Service cannot create process namespaces",
    1205             :                 .description_bad = "Service may create process namespaces",
    1206             :                 .weight = 500,
    1207             :                 .range = 1,
    1208             :                 .assess = assess_restrict_namespaces,
    1209             :                 .parameter = CLONE_NEWPID,
    1210             :         },
    1211             :         {
    1212             :                 .id = "RestrictNamespaces=~CLONE_NEWCGROUP",
    1213             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
    1214             :                 .description_good = "Service cannot create cgroup namespaces",
    1215             :                 .description_bad = "Service may create cgroup namespaces",
    1216             :                 .weight = 500,
    1217             :                 .range = 1,
    1218             :                 .assess = assess_restrict_namespaces,
    1219             :                 .parameter = CLONE_NEWCGROUP,
    1220             :         },
    1221             :         {
    1222             :                 .id = "RestrictNamespaces=~CLONE_NEWNET",
    1223             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
    1224             :                 .description_good = "Service cannot create network namespaces",
    1225             :                 .description_bad = "Service may create network namespaces",
    1226             :                 .weight = 500,
    1227             :                 .range = 1,
    1228             :                 .assess = assess_restrict_namespaces,
    1229             :                 .parameter = CLONE_NEWNET,
    1230             :         },
    1231             :         {
    1232             :                 .id = "RestrictNamespaces=~CLONE_NEWUTS",
    1233             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
    1234             :                 .description_good = "Service cannot create hostname namespaces",
    1235             :                 .description_bad = "Service may create hostname namespaces",
    1236             :                 .weight = 100,
    1237             :                 .range = 1,
    1238             :                 .assess = assess_restrict_namespaces,
    1239             :                 .parameter = CLONE_NEWUTS,
    1240             :         },
    1241             :         {
    1242             :                 .id = "RestrictAddressFamilies=~AF_(INET|INET6)",
    1243             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
    1244             :                 .description_good = "Service cannot allocate Internet sockets",
    1245             :                 .description_bad = "Service may allocate Internet sockets",
    1246             :                 .weight = 1500,
    1247             :                 .range = 1,
    1248             :                 .assess = assess_bool,
    1249             :                 .offset = offsetof(struct security_info, restrict_address_family_inet),
    1250             :         },
    1251             :         {
    1252             :                 .id = "RestrictAddressFamilies=~AF_UNIX",
    1253             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
    1254             :                 .description_good = "Service cannot allocate local sockets",
    1255             :                 .description_bad = "Service may allocate local sockets",
    1256             :                 .weight = 25,
    1257             :                 .range = 1,
    1258             :                 .assess = assess_bool,
    1259             :                 .offset = offsetof(struct security_info, restrict_address_family_unix),
    1260             :         },
    1261             :         {
    1262             :                 .id = "RestrictAddressFamilies=~AF_NETLINK",
    1263             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
    1264             :                 .description_good = "Service cannot allocate netlink sockets",
    1265             :                 .description_bad = "Service may allocate netlink sockets",
    1266             :                 .weight = 200,
    1267             :                 .range = 1,
    1268             :                 .assess = assess_bool,
    1269             :                 .offset = offsetof(struct security_info, restrict_address_family_netlink),
    1270             :         },
    1271             :         {
    1272             :                 .id = "RestrictAddressFamilies=~AF_PACKET",
    1273             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
    1274             :                 .description_good = "Service cannot allocate packet sockets",
    1275             :                 .description_bad = "Service may allocate packet sockets",
    1276             :                 .weight = 1000,
    1277             :                 .range = 1,
    1278             :                 .assess = assess_bool,
    1279             :                 .offset = offsetof(struct security_info, restrict_address_family_packet),
    1280             :         },
    1281             :         {
    1282             :                 .id = "RestrictAddressFamilies=~…",
    1283             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
    1284             :                 .description_good = "Service cannot allocate exotic sockets",
    1285             :                 .description_bad = "Service may allocate exotic sockets",
    1286             :                 .weight = 1250,
    1287             :                 .range = 1,
    1288             :                 .assess = assess_bool,
    1289             :                 .offset = offsetof(struct security_info, restrict_address_family_other),
    1290             :         },
    1291             :         {
    1292             :                 .id = "SystemCallArchitectures=",
    1293             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallArchitectures=",
    1294             :                 .weight = 1000,
    1295             :                 .range = 10,
    1296             :                 .assess = assess_system_call_architectures,
    1297             :         },
    1298             : #if HAVE_SECCOMP
    1299             :         {
    1300             :                 .id = "SystemCallFilter=~@swap",
    1301             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1302             :                 .weight = 1000,
    1303             :                 .range = 10,
    1304             :                 .assess = assess_system_call_filter,
    1305             :                 .parameter = SYSCALL_FILTER_SET_SWAP,
    1306             :         },
    1307             :         {
    1308             :                 .id = "SystemCallFilter=~@obsolete",
    1309             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1310             :                 .weight = 250,
    1311             :                 .range = 10,
    1312             :                 .assess = assess_system_call_filter,
    1313             :                 .parameter = SYSCALL_FILTER_SET_OBSOLETE,
    1314             :         },
    1315             :         {
    1316             :                 .id = "SystemCallFilter=~@clock",
    1317             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1318             :                 .weight = 1000,
    1319             :                 .range = 10,
    1320             :                 .assess = assess_system_call_filter,
    1321             :                 .parameter = SYSCALL_FILTER_SET_CLOCK,
    1322             :         },
    1323             :         {
    1324             :                 .id = "SystemCallFilter=~@cpu-emulation",
    1325             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1326             :                 .weight = 250,
    1327             :                 .range = 10,
    1328             :                 .assess = assess_system_call_filter,
    1329             :                 .parameter = SYSCALL_FILTER_SET_CPU_EMULATION,
    1330             :         },
    1331             :         {
    1332             :                 .id = "SystemCallFilter=~@debug",
    1333             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1334             :                 .weight = 1000,
    1335             :                 .range = 10,
    1336             :                 .assess = assess_system_call_filter,
    1337             :                 .parameter = SYSCALL_FILTER_SET_DEBUG,
    1338             :         },
    1339             :         {
    1340             :                 .id = "SystemCallFilter=~@mount",
    1341             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1342             :                 .weight = 1000,
    1343             :                 .range = 10,
    1344             :                 .assess = assess_system_call_filter,
    1345             :                 .parameter = SYSCALL_FILTER_SET_MOUNT,
    1346             :         },
    1347             :         {
    1348             :                 .id = "SystemCallFilter=~@module",
    1349             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1350             :                 .weight = 1000,
    1351             :                 .range = 10,
    1352             :                 .assess = assess_system_call_filter,
    1353             :                 .parameter = SYSCALL_FILTER_SET_MODULE,
    1354             :         },
    1355             :         {
    1356             :                 .id = "SystemCallFilter=~@raw-io",
    1357             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1358             :                 .weight = 1000,
    1359             :                 .range = 10,
    1360             :                 .assess = assess_system_call_filter,
    1361             :                 .parameter = SYSCALL_FILTER_SET_RAW_IO,
    1362             :         },
    1363             :         {
    1364             :                 .id = "SystemCallFilter=~@reboot",
    1365             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1366             :                 .weight = 1000,
    1367             :                 .range = 10,
    1368             :                 .assess = assess_system_call_filter,
    1369             :                 .parameter = SYSCALL_FILTER_SET_REBOOT,
    1370             :         },
    1371             :         {
    1372             :                 .id = "SystemCallFilter=~@privileged",
    1373             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1374             :                 .weight = 700,
    1375             :                 .range = 10,
    1376             :                 .assess = assess_system_call_filter,
    1377             :                 .parameter = SYSCALL_FILTER_SET_PRIVILEGED,
    1378             :         },
    1379             :         {
    1380             :                 .id = "SystemCallFilter=~@resources",
    1381             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
    1382             :                 .weight = 700,
    1383             :                 .range = 10,
    1384             :                 .assess = assess_system_call_filter,
    1385             :                 .parameter = SYSCALL_FILTER_SET_RESOURCES,
    1386             :         },
    1387             : #endif
    1388             :         {
    1389             :                 .id = "IPAddressDeny=",
    1390             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#IPAddressDeny=",
    1391             :                 .weight = 1000,
    1392             :                 .range = 10,
    1393             :                 .assess = assess_ip_address_allow,
    1394             :         },
    1395             :         {
    1396             :                 .id = "DeviceAllow=",
    1397             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#DeviceAllow=",
    1398             :                 .weight = 1000,
    1399             :                 .range = 10,
    1400             :                 .assess = assess_device_allow,
    1401             :         },
    1402             :         {
    1403             :                 .id = "AmbientCapabilities=",
    1404             :                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#AmbientCapabilities=",
    1405             :                 .description_good = "Service process does not receive ambient capabilities",
    1406             :                 .description_bad = "Service process receives ambient capabilities",
    1407             :                 .weight = 500,
    1408             :                 .range = 1,
    1409             :                 .assess = assess_ambient_capabilities,
    1410             :         },
    1411             : };
    1412             : 
    1413           0 : static int assess(const struct security_info *info, Table *overview_table, AnalyzeSecurityFlags flags) {
    1414             :         static const struct {
    1415             :                 uint64_t exposure;
    1416             :                 const char *name;
    1417             :                 const char *color;
    1418             :                 SpecialGlyph smiley;
    1419             :         } badness_table[] = {
    1420             :                 { 100, "DANGEROUS", ANSI_HIGHLIGHT_RED,    SPECIAL_GLYPH_DEPRESSED_SMILEY        },
    1421             :                 { 90,  "UNSAFE",    ANSI_HIGHLIGHT_RED,    SPECIAL_GLYPH_UNHAPPY_SMILEY          },
    1422             :                 { 75,  "EXPOSED",   ANSI_HIGHLIGHT_YELLOW, SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY },
    1423             :                 { 50,  "MEDIUM",    NULL,                  SPECIAL_GLYPH_NEUTRAL_SMILEY          },
    1424             :                 { 10,  "OK",        ANSI_HIGHLIGHT_GREEN,  SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY   },
    1425             :                 { 1,   "SAFE",      ANSI_HIGHLIGHT_GREEN,  SPECIAL_GLYPH_HAPPY_SMILEY            },
    1426             :                 { 0,   "PERFECT",   ANSI_HIGHLIGHT_GREEN,  SPECIAL_GLYPH_ECSTATIC_SMILEY         },
    1427             :         };
    1428             : 
    1429           0 :         uint64_t badness_sum = 0, weight_sum = 0, exposure;
    1430           0 :         _cleanup_(table_unrefp) Table *details_table = NULL;
    1431             :         size_t i;
    1432             :         int r;
    1433             : 
    1434           0 :         if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
    1435           0 :                 details_table = table_new(" ", "name", "description", "weight", "badness", "range", "exposure");
    1436           0 :                 if (!details_table)
    1437           0 :                         return log_oom();
    1438             : 
    1439           0 :                 (void) table_set_sort(details_table, 3, 1, (size_t) -1);
    1440           0 :                 (void) table_set_reverse(details_table, 3, true);
    1441             : 
    1442           0 :                 if (getenv_bool("SYSTEMD_ANALYZE_DEBUG") <= 0)
    1443           0 :                         (void) table_set_display(details_table, 0, 1, 2, 6, (size_t) -1);
    1444             :         }
    1445             : 
    1446           0 :         for (i = 0; i < ELEMENTSOF(security_assessor_table); i++) {
    1447           0 :                 const struct security_assessor *a = security_assessor_table + i;
    1448           0 :                 _cleanup_free_ char *d = NULL;
    1449             :                 uint64_t badness;
    1450             :                 void *data;
    1451             : 
    1452           0 :                 data = (uint8_t *) info + a->offset;
    1453             : 
    1454           0 :                 if (a->default_dependencies_only && !info->default_dependencies) {
    1455           0 :                         badness = UINT64_MAX;
    1456           0 :                         d = strdup("Service runs in special boot phase, option does not apply");
    1457           0 :                         if (!d)
    1458           0 :                                 return log_oom();
    1459             :                 } else {
    1460           0 :                         r = a->assess(a, info, data, &badness, &d);
    1461           0 :                         if (r < 0)
    1462           0 :                                 return r;
    1463             :                 }
    1464             : 
    1465           0 :                 assert(a->range > 0);
    1466             : 
    1467           0 :                 if (badness != UINT64_MAX) {
    1468           0 :                         assert(badness <= a->range);
    1469             : 
    1470           0 :                         badness_sum += DIV_ROUND_UP(badness * a->weight, a->range);
    1471           0 :                         weight_sum += a->weight;
    1472             :                 }
    1473             : 
    1474           0 :                 if (details_table) {
    1475           0 :                         const char *checkmark, *description, *color = NULL;
    1476             :                         TableCell *cell;
    1477             : 
    1478           0 :                         if (badness == UINT64_MAX) {
    1479           0 :                                 checkmark = " ";
    1480           0 :                                 description = a->description_na;
    1481           0 :                                 color = NULL;
    1482           0 :                         } else if (badness == a->range) {
    1483           0 :                                 checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
    1484           0 :                                 description = a->description_bad;
    1485           0 :                                 color = ansi_highlight_red();
    1486           0 :                         } else if (badness == 0) {
    1487           0 :                                 checkmark = special_glyph(SPECIAL_GLYPH_CHECK_MARK);
    1488           0 :                                 description = a->description_good;
    1489           0 :                                 color = ansi_highlight_green();
    1490             :                         } else {
    1491           0 :                                 checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
    1492           0 :                                 description = NULL;
    1493           0 :                                 color = ansi_highlight_red();
    1494             :                         }
    1495             : 
    1496           0 :                         if (d)
    1497           0 :                                 description = d;
    1498             : 
    1499           0 :                         r = table_add_cell_full(details_table, &cell, TABLE_STRING, checkmark, 1, 1, 0, 0, 0);
    1500           0 :                         if (r < 0)
    1501           0 :                                 return log_error_errno(r, "Failed to add cell to table: %m");
    1502           0 :                         if (color)
    1503           0 :                                 (void) table_set_color(details_table, cell, color);
    1504             : 
    1505           0 :                         r = table_add_many(details_table,
    1506             :                                            TABLE_STRING, a->id, TABLE_SET_URL, a->url,
    1507             :                                            TABLE_STRING, description,
    1508             :                                            TABLE_UINT64, a->weight, TABLE_SET_ALIGN_PERCENT, 100,
    1509             :                                            TABLE_UINT64, badness, TABLE_SET_ALIGN_PERCENT, 100,
    1510             :                                            TABLE_UINT64, a->range, TABLE_SET_ALIGN_PERCENT, 100,
    1511             :                                            TABLE_EMPTY, TABLE_SET_ALIGN_PERCENT, 100);
    1512           0 :                         if (r < 0)
    1513           0 :                                 return log_error_errno(r, "Failed to add cells to table: %m");
    1514             :                 }
    1515             :         }
    1516             : 
    1517           0 :         assert(weight_sum > 0);
    1518             : 
    1519           0 :         if (details_table) {
    1520             :                 size_t row;
    1521             : 
    1522           0 :                 for (row = 1; row < table_get_rows(details_table); row++) {
    1523             :                         char buf[DECIMAL_STR_MAX(uint64_t) + 1 + DECIMAL_STR_MAX(uint64_t) + 1];
    1524             :                         const uint64_t *weight, *badness, *range;
    1525             :                         TableCell *cell;
    1526             :                         uint64_t x;
    1527             : 
    1528           0 :                         assert_se(weight = table_get_at(details_table, row, 3));
    1529           0 :                         assert_se(badness = table_get_at(details_table, row, 4));
    1530           0 :                         assert_se(range = table_get_at(details_table, row, 5));
    1531             : 
    1532           0 :                         if (*badness == UINT64_MAX || *badness == 0)
    1533           0 :                                 continue;
    1534             : 
    1535           0 :                         assert_se(cell = table_get_cell(details_table, row, 6));
    1536             : 
    1537           0 :                         x = DIV_ROUND_UP(DIV_ROUND_UP(*badness * *weight * 100U, *range), weight_sum);
    1538           0 :                         xsprintf(buf, "%" PRIu64 ".%" PRIu64, x / 10, x % 10);
    1539             : 
    1540           0 :                         r = table_update(details_table, cell, TABLE_STRING, buf);
    1541           0 :                         if (r < 0)
    1542           0 :                                 return log_error_errno(r, "Failed to update cell in table: %m");
    1543             :                 }
    1544             : 
    1545           0 :                 r = table_print(details_table, stdout);
    1546           0 :                 if (r < 0)
    1547           0 :                         return log_error_errno(r, "Failed to output table: %m");
    1548             :         }
    1549             : 
    1550           0 :         exposure = DIV_ROUND_UP(badness_sum * 100U, weight_sum);
    1551             : 
    1552           0 :         for (i = 0; i < ELEMENTSOF(badness_table); i++)
    1553           0 :                 if (exposure >= badness_table[i].exposure)
    1554           0 :                         break;
    1555             : 
    1556           0 :         assert(i < ELEMENTSOF(badness_table));
    1557             : 
    1558           0 :         if (details_table) {
    1559           0 :                 _cleanup_free_ char *clickable = NULL;
    1560             :                 const char *name;
    1561             : 
    1562             :                 /* If we shall output the details table, also print the brief summary underneath */
    1563             : 
    1564           0 :                 if (info->fragment_path) {
    1565           0 :                         r = terminal_urlify_path(info->fragment_path, info->id, &clickable);
    1566           0 :                         if (r < 0)
    1567           0 :                                 return log_oom();
    1568             : 
    1569           0 :                         name = clickable;
    1570             :                 } else
    1571           0 :                         name = info->id;
    1572             : 
    1573           0 :                 printf("\n%s %sOverall exposure level for %s%s: %s%" PRIu64 ".%" PRIu64 " %s%s %s\n",
    1574             :                        special_glyph(SPECIAL_GLYPH_ARROW),
    1575             :                        ansi_highlight(),
    1576             :                        name,
    1577             :                        ansi_normal(),
    1578           0 :                        colors_enabled() ? strempty(badness_table[i].color) : "",
    1579             :                        exposure / 10, exposure % 10,
    1580             :                        badness_table[i].name,
    1581             :                        ansi_normal(),
    1582             :                        special_glyph(badness_table[i].smiley));
    1583             :         }
    1584             : 
    1585           0 :         fflush(stdout);
    1586             : 
    1587           0 :         if (overview_table) {
    1588             :                 char buf[DECIMAL_STR_MAX(uint64_t) + 1 + DECIMAL_STR_MAX(uint64_t) + 1];
    1589             :                 TableCell *cell;
    1590             : 
    1591           0 :                 r = table_add_cell(overview_table, &cell, TABLE_STRING, info->id);
    1592           0 :                 if (r < 0)
    1593           0 :                         return log_error_errno(r, "Failed to add cell to table: %m");
    1594           0 :                 if (info->fragment_path) {
    1595           0 :                         _cleanup_free_ char *url = NULL;
    1596             : 
    1597           0 :                         r = file_url_from_path(info->fragment_path, &url);
    1598           0 :                         if (r < 0)
    1599           0 :                                 return log_error_errno(r, "Failed to generate URL from path: %m");
    1600             : 
    1601           0 :                         (void) table_set_url(overview_table, cell, url);
    1602             :                 }
    1603             : 
    1604           0 :                 xsprintf(buf, "%" PRIu64 ".%" PRIu64, exposure / 10, exposure % 10);
    1605           0 :                 r = table_add_cell(overview_table, &cell, TABLE_STRING, buf);
    1606           0 :                 if (r < 0)
    1607           0 :                         return log_error_errno(r, "Failed to add cell to table: %m");
    1608           0 :                 (void) table_set_align_percent(overview_table, cell, 100);
    1609             : 
    1610           0 :                 r = table_add_cell(overview_table, &cell, TABLE_STRING, badness_table[i].name);
    1611           0 :                 if (r < 0)
    1612           0 :                         return log_error_errno(r, "Failed to add cell to table: %m");
    1613           0 :                 (void) table_set_color(overview_table, cell, strempty(badness_table[i].color));
    1614             : 
    1615           0 :                 r = table_add_cell(overview_table, NULL, TABLE_STRING, special_glyph(badness_table[i].smiley));
    1616           0 :                 if (r < 0)
    1617           0 :                         return log_error_errno(r, "Failed to add cell to table: %m");
    1618             :         }
    1619             : 
    1620           0 :         return 0;
    1621             : }
    1622             : 
    1623           0 : static int property_read_restrict_address_families(
    1624             :                 sd_bus *bus,
    1625             :                 const char *member,
    1626             :                 sd_bus_message *m,
    1627             :                 sd_bus_error *error,
    1628             :                 void *userdata) {
    1629             : 
    1630           0 :         struct security_info *info = userdata;
    1631             :         int whitelist, r;
    1632             : 
    1633           0 :         assert(bus);
    1634           0 :         assert(member);
    1635           0 :         assert(m);
    1636             : 
    1637           0 :         r = sd_bus_message_enter_container(m, 'r', "bas");
    1638           0 :         if (r < 0)
    1639           0 :                 return r;
    1640             : 
    1641           0 :         r = sd_bus_message_read(m, "b", &whitelist);
    1642           0 :         if (r < 0)
    1643           0 :                 return r;
    1644             : 
    1645           0 :         info->restrict_address_family_inet =
    1646           0 :                 info->restrict_address_family_unix =
    1647           0 :                 info->restrict_address_family_netlink =
    1648           0 :                 info->restrict_address_family_packet =
    1649           0 :                 info->restrict_address_family_other = whitelist;
    1650             : 
    1651           0 :         r = sd_bus_message_enter_container(m, 'a', "s");
    1652           0 :         if (r < 0)
    1653           0 :                 return r;
    1654             : 
    1655           0 :         for (;;) {
    1656             :                 const char *name;
    1657             : 
    1658           0 :                 r = sd_bus_message_read(m, "s", &name);
    1659           0 :                 if (r < 0)
    1660           0 :                         return r;
    1661           0 :                 if (r == 0)
    1662           0 :                         break;
    1663             : 
    1664           0 :                 if (STR_IN_SET(name, "AF_INET", "AF_INET6"))
    1665           0 :                         info->restrict_address_family_inet = !whitelist;
    1666           0 :                 else if (streq(name, "AF_UNIX"))
    1667           0 :                         info->restrict_address_family_unix = !whitelist;
    1668           0 :                 else if (streq(name, "AF_NETLINK"))
    1669           0 :                         info->restrict_address_family_netlink = !whitelist;
    1670           0 :                 else if (streq(name, "AF_PACKET"))
    1671           0 :                         info->restrict_address_family_packet = !whitelist;
    1672             :                 else
    1673           0 :                         info->restrict_address_family_other = !whitelist;
    1674             :         }
    1675             : 
    1676           0 :         r = sd_bus_message_exit_container(m);
    1677           0 :         if (r < 0)
    1678           0 :                 return r;
    1679             : 
    1680           0 :         return sd_bus_message_exit_container(m);
    1681             : }
    1682             : 
    1683           0 : static int property_read_system_call_filter(
    1684             :                 sd_bus *bus,
    1685             :                 const char *member,
    1686             :                 sd_bus_message *m,
    1687             :                 sd_bus_error *error,
    1688             :                 void *userdata) {
    1689             : 
    1690           0 :         struct security_info *info = userdata;
    1691             :         int whitelist, r;
    1692             : 
    1693           0 :         assert(bus);
    1694           0 :         assert(member);
    1695           0 :         assert(m);
    1696             : 
    1697           0 :         r = sd_bus_message_enter_container(m, 'r', "bas");
    1698           0 :         if (r < 0)
    1699           0 :                 return r;
    1700             : 
    1701           0 :         r = sd_bus_message_read(m, "b", &whitelist);
    1702           0 :         if (r < 0)
    1703           0 :                 return r;
    1704             : 
    1705           0 :         info->system_call_filter_whitelist = whitelist;
    1706             : 
    1707           0 :         r = sd_bus_message_enter_container(m, 'a', "s");
    1708           0 :         if (r < 0)
    1709           0 :                 return r;
    1710             : 
    1711           0 :         for (;;) {
    1712             :                 const char *name;
    1713             : 
    1714           0 :                 r = sd_bus_message_read(m, "s", &name);
    1715           0 :                 if (r < 0)
    1716           0 :                         return r;
    1717           0 :                 if (r == 0)
    1718           0 :                         break;
    1719             : 
    1720           0 :                 r = set_ensure_allocated(&info->system_call_filter, &string_hash_ops);
    1721           0 :                 if (r < 0)
    1722           0 :                         return r;
    1723             : 
    1724           0 :                 r = set_put_strdup(info->system_call_filter, name);
    1725           0 :                 if (r < 0)
    1726           0 :                         return r;
    1727             :         }
    1728             : 
    1729           0 :         r = sd_bus_message_exit_container(m);
    1730           0 :         if (r < 0)
    1731           0 :                 return r;
    1732             : 
    1733           0 :         return sd_bus_message_exit_container(m);
    1734             : }
    1735             : 
    1736           0 : static int property_read_ip_address_allow(
    1737             :                 sd_bus *bus,
    1738             :                 const char *member,
    1739             :                 sd_bus_message *m,
    1740             :                 sd_bus_error *error,
    1741             :                 void *userdata) {
    1742             : 
    1743           0 :         struct security_info *info = userdata;
    1744           0 :         bool deny_ipv4 = false, deny_ipv6 = false;
    1745             :         int r;
    1746             : 
    1747           0 :         assert(bus);
    1748           0 :         assert(member);
    1749           0 :         assert(m);
    1750             : 
    1751           0 :         r = sd_bus_message_enter_container(m, 'a', "(iayu)");
    1752           0 :         if (r < 0)
    1753           0 :                 return r;
    1754             : 
    1755           0 :         for (;;) {
    1756             :                 const void *data;
    1757             :                 size_t size;
    1758             :                 int32_t family;
    1759             :                 uint32_t prefixlen;
    1760             : 
    1761           0 :                 r = sd_bus_message_enter_container(m, 'r', "iayu");
    1762           0 :                 if (r < 0)
    1763           0 :                         return r;
    1764           0 :                 if (r == 0)
    1765           0 :                         break;
    1766             : 
    1767           0 :                 r = sd_bus_message_read(m, "i", &family);
    1768           0 :                 if (r < 0)
    1769           0 :                         return r;
    1770             : 
    1771           0 :                 r = sd_bus_message_read_array(m, 'y', &data, &size);
    1772           0 :                 if (r < 0)
    1773           0 :                         return r;
    1774             : 
    1775           0 :                 r = sd_bus_message_read(m, "u", &prefixlen);
    1776           0 :                 if (r < 0)
    1777           0 :                         return r;
    1778             : 
    1779           0 :                 r = sd_bus_message_exit_container(m);
    1780           0 :                 if (r < 0)
    1781           0 :                         return r;
    1782             : 
    1783           0 :                 if (streq(member, "IPAddressAllow")) {
    1784             :                         union in_addr_union u;
    1785             : 
    1786           0 :                         if (family == AF_INET && size == 4 && prefixlen == 8)
    1787           0 :                                 memcpy(&u.in, data, size);
    1788           0 :                         else if (family == AF_INET6 && size == 16 && prefixlen == 128)
    1789           0 :                                 memcpy(&u.in6, data, size);
    1790             :                         else {
    1791           0 :                                 info->ip_address_allow_other = true;
    1792           0 :                                 continue;
    1793             :                         }
    1794             : 
    1795           0 :                         if (in_addr_is_localhost(family, &u))
    1796           0 :                                 info->ip_address_allow_localhost = true;
    1797             :                         else
    1798           0 :                                 info->ip_address_allow_other = true;
    1799             :                 } else {
    1800           0 :                         assert(streq(member, "IPAddressDeny"));
    1801             : 
    1802           0 :                         if (family == AF_INET && size == 4 && prefixlen == 0)
    1803           0 :                                 deny_ipv4 = true;
    1804           0 :                         else if (family == AF_INET6 && size == 16 && prefixlen == 0)
    1805           0 :                                 deny_ipv6 = true;
    1806             :                 }
    1807             :         }
    1808             : 
    1809           0 :         info->ip_address_deny_all = deny_ipv4 && deny_ipv6;
    1810             : 
    1811           0 :         return sd_bus_message_exit_container(m);
    1812             : }
    1813             : 
    1814           0 : static int property_read_ip_filters(
    1815             :                 sd_bus *bus,
    1816             :                 const char *member,
    1817             :                 sd_bus_message *m,
    1818             :                 sd_bus_error *error,
    1819             :                 void *userdata) {
    1820             : 
    1821           0 :         struct security_info *info = userdata;
    1822           0 :         _cleanup_(strv_freep) char **l = NULL;
    1823             :         int r;
    1824             : 
    1825           0 :         assert(bus);
    1826           0 :         assert(member);
    1827           0 :         assert(m);
    1828             : 
    1829           0 :         r = sd_bus_message_read_strv(m, &l);
    1830           0 :         if (r < 0)
    1831           0 :                 return r;
    1832             : 
    1833           0 :         if (streq(member, "IPIngressFilterPath"))
    1834           0 :                 info->ip_filters_custom_ingress = !strv_isempty(l);
    1835           0 :         else if (streq(member, "IPEgressFilterPath"))
    1836           0 :                 info->ip_filters_custom_ingress = !strv_isempty(l);
    1837             : 
    1838           0 :         return 0;
    1839             : }
    1840             : 
    1841           0 : static int property_read_device_allow(
    1842             :                 sd_bus *bus,
    1843             :                 const char *member,
    1844             :                 sd_bus_message *m,
    1845             :                 sd_bus_error *error,
    1846             :                 void *userdata) {
    1847             : 
    1848           0 :         struct security_info *info = userdata;
    1849           0 :         size_t n = 0;
    1850             :         int r;
    1851             : 
    1852           0 :         assert(bus);
    1853           0 :         assert(member);
    1854           0 :         assert(m);
    1855             : 
    1856           0 :         r = sd_bus_message_enter_container(m, 'a', "(ss)");
    1857           0 :         if (r < 0)
    1858           0 :                 return r;
    1859             : 
    1860           0 :         for (;;) {
    1861             :                 const char *name, *policy;
    1862             : 
    1863           0 :                 r = sd_bus_message_read(m, "(ss)", &name, &policy);
    1864           0 :                 if (r < 0)
    1865           0 :                         return r;
    1866           0 :                 if (r == 0)
    1867           0 :                         break;
    1868             : 
    1869           0 :                 n++;
    1870             :         }
    1871             : 
    1872           0 :         info->device_allow_non_empty = n > 0;
    1873             : 
    1874           0 :         return sd_bus_message_exit_container(m);
    1875             : }
    1876             : 
    1877           0 : static int acquire_security_info(sd_bus *bus, const char *name, struct security_info *info, AnalyzeSecurityFlags flags) {
    1878             : 
    1879             :         static const struct bus_properties_map security_map[] = {
    1880             :                 { "AmbientCapabilities",     "t",       NULL,                                    offsetof(struct security_info, ambient_capabilities)      },
    1881             :                 { "CapabilityBoundingSet",   "t",       NULL,                                    offsetof(struct security_info, capability_bounding_set)   },
    1882             :                 { "DefaultDependencies",     "b",       NULL,                                    offsetof(struct security_info, default_dependencies)      },
    1883             :                 { "Delegate",                "b",       NULL,                                    offsetof(struct security_info, delegate)                  },
    1884             :                 { "DeviceAllow",             "a(ss)",   property_read_device_allow,              0                                                         },
    1885             :                 { "DevicePolicy",            "s",       NULL,                                    offsetof(struct security_info, device_policy)             },
    1886             :                 { "DynamicUser",             "b",       NULL,                                    offsetof(struct security_info, dynamic_user)              },
    1887             :                 { "FragmentPath",            "s",       NULL,                                    offsetof(struct security_info, fragment_path)             },
    1888             :                 { "IPAddressAllow",          "a(iayu)", property_read_ip_address_allow,          0                                                         },
    1889             :                 { "IPAddressDeny",           "a(iayu)", property_read_ip_address_allow,          0                                                         },
    1890             :                 { "IPIngressFilterPath",     "as",      property_read_ip_filters,                0                                                         },
    1891             :                 { "IPEgressFilterPath",      "as",      property_read_ip_filters,                0                                                         },
    1892             :                 { "Id",                      "s",       NULL,                                    offsetof(struct security_info, id)                        },
    1893             :                 { "KeyringMode",             "s",       NULL,                                    offsetof(struct security_info, keyring_mode)              },
    1894             :                 { "LoadState",               "s",       NULL,                                    offsetof(struct security_info, load_state)                },
    1895             :                 { "LockPersonality",         "b",       NULL,                                    offsetof(struct security_info, lock_personality)          },
    1896             :                 { "MemoryDenyWriteExecute",  "b",       NULL,                                    offsetof(struct security_info, memory_deny_write_execute) },
    1897             :                 { "NoNewPrivileges",         "b",       NULL,                                    offsetof(struct security_info, no_new_privileges)         },
    1898             :                 { "NotifyAccess",            "s",       NULL,                                    offsetof(struct security_info, notify_access)             },
    1899             :                 { "PrivateDevices",          "b",       NULL,                                    offsetof(struct security_info, private_devices)           },
    1900             :                 { "PrivateMounts",           "b",       NULL,                                    offsetof(struct security_info, private_mounts)            },
    1901             :                 { "PrivateNetwork",          "b",       NULL,                                    offsetof(struct security_info, private_network)           },
    1902             :                 { "PrivateTmp",              "b",       NULL,                                    offsetof(struct security_info, private_tmp)               },
    1903             :                 { "PrivateUsers",            "b",       NULL,                                    offsetof(struct security_info, private_users)             },
    1904             :                 { "ProtectControlGroups",    "b",       NULL,                                    offsetof(struct security_info, protect_control_groups)    },
    1905             :                 { "ProtectHome",             "s",       NULL,                                    offsetof(struct security_info, protect_home)              },
    1906             :                 { "ProtectHostname",         "b",       NULL,                                    offsetof(struct security_info, protect_hostname)          },
    1907             :                 { "ProtectKernelModules",    "b",       NULL,                                    offsetof(struct security_info, protect_kernel_modules)    },
    1908             :                 { "ProtectKernelTunables",   "b",       NULL,                                    offsetof(struct security_info, protect_kernel_tunables)   },
    1909             :                 { "ProtectSystem",           "s",       NULL,                                    offsetof(struct security_info, protect_system)            },
    1910             :                 { "RemoveIPC",               "b",       NULL,                                    offsetof(struct security_info, remove_ipc)                },
    1911             :                 { "RestrictAddressFamilies", "(bas)",   property_read_restrict_address_families, 0                                                         },
    1912             :                 { "RestrictNamespaces",      "t",       NULL,                                    offsetof(struct security_info, restrict_namespaces)       },
    1913             :                 { "RestrictRealtime",        "b",       NULL,                                    offsetof(struct security_info, restrict_realtime)         },
    1914             :                 { "RestrictSUIDSGID",        "b",       NULL,                                    offsetof(struct security_info, restrict_suid_sgid)        },
    1915             :                 { "RootDirectory",           "s",       NULL,                                    offsetof(struct security_info, root_directory)            },
    1916             :                 { "RootImage",               "s",       NULL,                                    offsetof(struct security_info, root_image)                },
    1917             :                 { "SupplementaryGroups",     "as",      NULL,                                    offsetof(struct security_info, supplementary_groups)      },
    1918             :                 { "SystemCallArchitectures", "as",      NULL,                                    offsetof(struct security_info, system_call_architectures) },
    1919             :                 { "SystemCallFilter",        "(as)",    property_read_system_call_filter,        0                                                         },
    1920             :                 { "Type",                    "s",       NULL,                                    offsetof(struct security_info, type)                      },
    1921             :                 { "UMask",                   "u",       NULL,                                    offsetof(struct security_info, _umask)                    },
    1922             :                 { "User",                    "s",       NULL,                                    offsetof(struct security_info, user)                      },
    1923             :                 {}
    1924             :         };
    1925             : 
    1926           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1927           0 :         _cleanup_free_ char *path = NULL;
    1928             :         int r;
    1929             : 
    1930             :         /* Note: this mangles *info on failure! */
    1931             : 
    1932           0 :         assert(bus);
    1933           0 :         assert(name);
    1934           0 :         assert(info);
    1935             : 
    1936           0 :         path = unit_dbus_path_from_name(name);
    1937           0 :         if (!path)
    1938           0 :                 return log_oom();
    1939             : 
    1940           0 :         r = bus_map_all_properties(
    1941             :                         bus,
    1942             :                         "org.freedesktop.systemd1",
    1943             :                         path,
    1944             :                         security_map,
    1945             :                         BUS_MAP_STRDUP | BUS_MAP_BOOLEAN_AS_BOOL,
    1946             :                         &error,
    1947             :                         NULL,
    1948             :                         info);
    1949           0 :         if (r < 0)
    1950           0 :                 return log_error_errno(r, "Failed to get unit properties: %s", bus_error_message(&error, r));
    1951             : 
    1952           0 :         if (!streq_ptr(info->load_state, "loaded")) {
    1953             : 
    1954           0 :                 if (FLAGS_SET(flags, ANALYZE_SECURITY_ONLY_LOADED))
    1955           0 :                         return -EMEDIUMTYPE;
    1956             : 
    1957           0 :                 if (streq_ptr(info->load_state, "not-found"))
    1958           0 :                         log_error("Unit %s not found, cannot analyze.", name);
    1959           0 :                 else if (streq_ptr(info->load_state, "masked"))
    1960           0 :                         log_error("Unit %s is masked, cannot analyze.", name);
    1961             :                 else
    1962           0 :                         log_error("Unit %s not loaded properly, cannot analyze.", name);
    1963             : 
    1964           0 :                 return -EINVAL;
    1965             :         }
    1966             : 
    1967           0 :         if (FLAGS_SET(flags, ANALYZE_SECURITY_ONLY_LONG_RUNNING) && streq_ptr(info->type, "oneshot"))
    1968           0 :                 return -EMEDIUMTYPE;
    1969             : 
    1970           0 :         if (info->private_devices ||
    1971           0 :             info->private_tmp ||
    1972           0 :             info->protect_control_groups ||
    1973           0 :             info->protect_kernel_tunables ||
    1974           0 :             info->protect_kernel_modules ||
    1975           0 :             !streq_ptr(info->protect_home, "no") ||
    1976           0 :             !streq_ptr(info->protect_system, "no") ||
    1977           0 :             info->root_image)
    1978           0 :                 info->private_mounts = true;
    1979             : 
    1980           0 :         if (info->protect_kernel_modules)
    1981           0 :                 info->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYS_MODULE);
    1982             : 
    1983           0 :         if (info->private_devices)
    1984           0 :                 info->capability_bounding_set &= ~((UINT64_C(1) << CAP_MKNOD) |
    1985             :                                                    (UINT64_C(1) << CAP_SYS_RAWIO));
    1986             : 
    1987           0 :         return 0;
    1988             : }
    1989             : 
    1990           0 : static int analyze_security_one(sd_bus *bus, const char *name, Table *overview_table, AnalyzeSecurityFlags flags) {
    1991           0 :         _cleanup_(security_info_free) struct security_info info = {
    1992             :                 .default_dependencies = true,
    1993             :                 .capability_bounding_set = UINT64_MAX,
    1994             :                 .restrict_namespaces = UINT64_MAX,
    1995             :                 ._umask = 0002,
    1996             :         };
    1997             :         int r;
    1998             : 
    1999           0 :         assert(bus);
    2000           0 :         assert(name);
    2001             : 
    2002           0 :         r = acquire_security_info(bus, name, &info, flags);
    2003           0 :         if (r == -EMEDIUMTYPE) /* Ignore this one because not loaded or Type is oneshot */
    2004           0 :                 return 0;
    2005           0 :         if (r < 0)
    2006           0 :                 return r;
    2007             : 
    2008           0 :         r = assess(&info, overview_table, flags);
    2009           0 :         if (r < 0)
    2010           0 :                 return r;
    2011             : 
    2012           0 :         return 0;
    2013             : }
    2014             : 
    2015           0 : int analyze_security(sd_bus *bus, char **units, AnalyzeSecurityFlags flags) {
    2016           0 :         _cleanup_(table_unrefp) Table *overview_table = NULL;
    2017           0 :         int ret = 0, r;
    2018             : 
    2019           0 :         assert(bus);
    2020             : 
    2021           0 :         if (strv_length(units) != 1) {
    2022           0 :                 overview_table = table_new("unit", "exposure", "predicate", "happy");
    2023           0 :                 if (!overview_table)
    2024           0 :                         return log_oom();
    2025             :         }
    2026             : 
    2027           0 :         if (strv_isempty(units)) {
    2028           0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    2029           0 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
    2030           0 :                 _cleanup_strv_free_ char **list = NULL;
    2031           0 :                 size_t allocated = 0, n = 0;
    2032             :                 char **i;
    2033             : 
    2034           0 :                 r = sd_bus_call_method(
    2035             :                                 bus,
    2036             :                                 "org.freedesktop.systemd1",
    2037             :                                 "/org/freedesktop/systemd1",
    2038             :                                 "org.freedesktop.systemd1.Manager",
    2039             :                                 "ListUnits",
    2040             :                                 &error,
    2041             :                                 &reply,
    2042             :                                 NULL);
    2043           0 :                 if (r < 0)
    2044           0 :                         return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
    2045             : 
    2046           0 :                 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
    2047           0 :                 if (r < 0)
    2048           0 :                         return bus_log_parse_error(r);
    2049             : 
    2050           0 :                 for (;;) {
    2051             :                         UnitInfo info;
    2052           0 :                         char *copy = NULL;
    2053             : 
    2054           0 :                         r = bus_parse_unit_info(reply, &info);
    2055           0 :                         if (r < 0)
    2056           0 :                                 return bus_log_parse_error(r);
    2057           0 :                         if (r == 0)
    2058           0 :                                 break;
    2059             : 
    2060           0 :                         if (!endswith(info.id, ".service"))
    2061           0 :                                 continue;
    2062             : 
    2063           0 :                         if (!GREEDY_REALLOC(list, allocated, n + 2))
    2064           0 :                                 return log_oom();
    2065             : 
    2066           0 :                         copy = strdup(info.id);
    2067           0 :                         if (!copy)
    2068           0 :                                 return log_oom();
    2069             : 
    2070           0 :                         list[n++] = copy;
    2071           0 :                         list[n] = NULL;
    2072             :                 }
    2073             : 
    2074           0 :                 strv_sort(list);
    2075             : 
    2076           0 :                 flags |= ANALYZE_SECURITY_SHORT|ANALYZE_SECURITY_ONLY_LOADED|ANALYZE_SECURITY_ONLY_LONG_RUNNING;
    2077             : 
    2078           0 :                 STRV_FOREACH(i, list) {
    2079           0 :                         r = analyze_security_one(bus, *i, overview_table, flags);
    2080           0 :                         if (r < 0 && ret >= 0)
    2081           0 :                                 ret = r;
    2082             :                 }
    2083             : 
    2084             :         } else {
    2085             :                 char **i;
    2086             : 
    2087           0 :                 STRV_FOREACH(i, units) {
    2088           0 :                         _cleanup_free_ char *mangled = NULL, *instance = NULL;
    2089             :                         const char *name;
    2090             : 
    2091           0 :                         if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT) && i != units) {
    2092           0 :                                 putc('\n', stdout);
    2093           0 :                                 fflush(stdout);
    2094             :                         }
    2095             : 
    2096           0 :                         r = unit_name_mangle_with_suffix(*i, 0, ".service", &mangled);
    2097           0 :                         if (r < 0)
    2098           0 :                                 return log_error_errno(r, "Failed to mangle unit name '%s': %m", *i);
    2099             : 
    2100           0 :                         if (!endswith(mangled, ".service")) {
    2101           0 :                                 log_error("Unit %s is not a service unit, refusing.", *i);
    2102           0 :                                 return -EINVAL;
    2103             :                         }
    2104             : 
    2105           0 :                         if (unit_name_is_valid(mangled, UNIT_NAME_TEMPLATE)) {
    2106           0 :                                 r = unit_name_replace_instance(mangled, "test-instance", &instance);
    2107           0 :                                 if (r < 0)
    2108           0 :                                         return log_oom();
    2109             : 
    2110           0 :                                 name = instance;
    2111             :                         } else
    2112           0 :                                 name = mangled;
    2113             : 
    2114           0 :                         r = analyze_security_one(bus, name, overview_table, flags);
    2115           0 :                         if (r < 0 && ret >= 0)
    2116           0 :                                 ret = r;
    2117             :                 }
    2118             :         }
    2119             : 
    2120           0 :         if (overview_table) {
    2121           0 :                 if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
    2122           0 :                         putc('\n', stdout);
    2123           0 :                         fflush(stdout);
    2124             :                 }
    2125             : 
    2126           0 :                 r = table_print(overview_table, stdout);
    2127           0 :                 if (r < 0)
    2128           0 :                         return log_error_errno(r, "Failed to output table: %m");
    2129             :         }
    2130             : 
    2131           0 :         return ret;
    2132             : }

Generated by: LCOV version 1.14