]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/analyze/analyze-security.c
Merge pull request #12121 from poettering/contrib
[thirdparty/systemd.git] / src / analyze / analyze-security.c
index f8ba743f73c292a3d0003fa5beb6048687d0bfe6..a9a93d0f076323c431a8bb1eb475d282aa2e677b 100644 (file)
@@ -12,6 +12,8 @@
 #include "in-addr-util.h"
 #include "locale-util.h"
 #include "macro.h"
+#include "missing.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "pretty-print.h"
@@ -48,6 +50,7 @@ struct security_info {
         bool memory_deny_write_execute;
         bool no_new_privileges;
         char *notify_access;
+        bool protect_hostname;
 
         bool private_devices;
         bool private_mounts;
@@ -72,6 +75,7 @@ struct security_info {
 
         uint64_t restrict_namespaces;
         bool restrict_realtime;
+        bool restrict_suid_sgid;
 
         char *root_directory;
         char *root_image;
@@ -293,10 +297,8 @@ static int assess_root_directory(
         assert(ret_description);
 
         *ret_badness =
-                (isempty(info->root_directory) ||
-                 path_equal(info->root_directory, "/")) &&
-                (isempty(info->root_image) ||
-                 path_equal(info->root_image, "/"));
+                empty_or_root(info->root_directory) ||
+                empty_or_root(info->root_image);
         *ret_description = NULL;
 
         return 0;
@@ -484,24 +486,24 @@ static bool syscall_names_in_filter(Set *s, bool whitelist, const SyscallFilterS
         const char *syscall;
 
         NULSTR_FOREACH(syscall, f->value) {
-                bool b;
+                int id;
 
                 if (syscall[0] == '@') {
                         const SyscallFilterSet *g;
-                        assert_se(g = syscall_filter_set_find(syscall));
-                        b = syscall_names_in_filter(s, whitelist, g);
-                } else {
-                        int id;
 
-                        /* Let's see if the system call actually exists on this platform, before complaining */
-                        id = seccomp_syscall_resolve_name(syscall);
-                        if (id < 0)
-                                continue;
+                        assert_se(g = syscall_filter_set_find(syscall));
+                        if (syscall_names_in_filter(s, whitelist, g))
+                                return true; /* bad! */
 
-                        b = set_contains(s, syscall);
+                        continue;
                 }
 
-                if (whitelist == b) {
+                /* Let's see if the system call actually exists on this platform, before complaining */
+                id = seccomp_syscall_resolve_name(syscall);
+                if (id < 0)
+                        continue;
+
+                if (set_contains(s, syscall) == whitelist) {
                         log_debug("Offending syscall filter item: %s", syscall);
                         return true; /* bad! */
                 }
@@ -767,6 +769,16 @@ static const struct security_assessor security_assessor_table[] = {
                 .assess = assess_protect_home,
                 .default_dependencies_only = true,
         },
+        {
+                .id = "ProtectHostname=",
+                .description_good = "Service cannot change system host/domainname",
+                .description_bad = "Service may change system host/domainname",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHostname=",
+                .weight = 50,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, protect_hostname),
+        },
         {
                 .id = "ProtectSystem=",
                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectSystem=",
@@ -1135,6 +1147,16 @@ static const struct security_assessor security_assessor_table[] = {
                 .assess = assess_bool,
                 .offset = offsetof(struct security_info, restrict_realtime),
         },
+        {
+                .id = "RestrictSUIDSGID=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictSUIDSGID=",
+                .description_good = "SUID/SGID file creation by service is restricted",
+                .description_bad = "Service may create SUID/SGID files",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, restrict_suid_sgid),
+        },
         {
                 .id = "RestrictNamespaces=~CLONE_NEWUSER",
                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
@@ -1384,13 +1406,13 @@ static int assess(const struct security_info *info, Table *overview_table, Analy
                 const char *color;
                 SpecialGlyph smiley;
         } badness_table[] = {
-                { 100, "DANGEROUS", ANSI_HIGHLIGHT_RED,    DEPRESSED_SMILEY        },
-                { 90,  "UNSAFE",    ANSI_HIGHLIGHT_RED,    UNHAPPY_SMILEY          },
-                { 75,  "EXPOSED",   ANSI_HIGHLIGHT_YELLOW, SLIGHTLY_UNHAPPY_SMILEY },
-                { 50,  "MEDIUM",    NULL,                  NEUTRAL_SMILEY          },
-                { 10,  "OK",        ANSI_HIGHLIGHT_GREEN,  SLIGHTLY_HAPPY_SMILEY   },
-                { 1,   "SAFE",      ANSI_HIGHLIGHT_GREEN,  HAPPY_SMILEY            },
-                { 0,   "PERFECT",   ANSI_HIGHLIGHT_GREEN,  ECSTATIC_SMILEY         },
+                { 100, "DANGEROUS", ANSI_HIGHLIGHT_RED,    SPECIAL_GLYPH_DEPRESSED_SMILEY        },
+                { 90,  "UNSAFE",    ANSI_HIGHLIGHT_RED,    SPECIAL_GLYPH_UNHAPPY_SMILEY          },
+                { 75,  "EXPOSED",   ANSI_HIGHLIGHT_YELLOW, SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY },
+                { 50,  "MEDIUM",    NULL,                  SPECIAL_GLYPH_NEUTRAL_SMILEY          },
+                { 10,  "OK",        ANSI_HIGHLIGHT_GREEN,  SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY   },
+                { 1,   "SAFE",      ANSI_HIGHLIGHT_GREEN,  SPECIAL_GLYPH_HAPPY_SMILEY            },
+                { 0,   "PERFECT",   ANSI_HIGHLIGHT_GREEN,  SPECIAL_GLYPH_ECSTATIC_SMILEY         },
         };
 
         uint64_t badness_sum = 0, weight_sum = 0, exposure;
@@ -1447,15 +1469,15 @@ static int assess(const struct security_info *info, Table *overview_table, Analy
                                 description = a->description_na;
                                 color = NULL;
                         } else if (badness == a->range) {
-                                checkmark = special_glyph(CROSS_MARK);
+                                checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
                                 description = a->description_bad;
                                 color = ansi_highlight_red();
                         } else if (badness == 0) {
-                                checkmark = special_glyph(CHECK_MARK);
+                                checkmark = special_glyph(SPECIAL_GLYPH_CHECK_MARK);
                                 description = a->description_good;
                                 color = ansi_highlight_green();
                         } else {
-                                checkmark = special_glyph(CROSS_MARK);
+                                checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
                                 description = NULL;
                                 color = ansi_highlight_red();
                         }
@@ -1532,6 +1554,7 @@ static int assess(const struct security_info *info, Table *overview_table, Analy
                         return log_error_errno(r, "Failed to output table: %m");
         }
 
+        assert(weight_sum > 0);
         exposure = DIV_ROUND_UP(badness_sum * 100U, weight_sum);
 
         for (i = 0; i < ELEMENTSOF(badness_table); i++)
@@ -1556,7 +1579,7 @@ static int assess(const struct security_info *info, Table *overview_table, Analy
                         name = info->id;
 
                 printf("\n%s %sOverall exposure level for %s%s: %s%" PRIu64 ".%" PRIu64 " %s%s %s\n",
-                       special_glyph(ARROW),
+                       special_glyph(SPECIAL_GLYPH_ARROW),
                        ansi_highlight(),
                        name,
                        ansi_normal(),
@@ -1857,9 +1880,9 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
                 { "PrivateNetwork",          "b",       NULL,                                    offsetof(struct security_info, private_network)           },
                 { "PrivateTmp",              "b",       NULL,                                    offsetof(struct security_info, private_tmp)               },
                 { "PrivateUsers",            "b",       NULL,                                    offsetof(struct security_info, private_users)             },
-                { "PrivateUsers",            "b",       NULL,                                    offsetof(struct security_info, private_users)             },
                 { "ProtectControlGroups",    "b",       NULL,                                    offsetof(struct security_info, protect_control_groups)    },
                 { "ProtectHome",             "s",       NULL,                                    offsetof(struct security_info, protect_home)              },
+                { "ProtectHostname",         "b",       NULL,                                    offsetof(struct security_info, protect_hostname)          },
                 { "ProtectKernelModules",    "b",       NULL,                                    offsetof(struct security_info, protect_kernel_modules)    },
                 { "ProtectKernelTunables",   "b",       NULL,                                    offsetof(struct security_info, protect_kernel_tunables)   },
                 { "ProtectSystem",           "s",       NULL,                                    offsetof(struct security_info, protect_system)            },
@@ -1867,6 +1890,7 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
                 { "RestrictAddressFamilies", "(bas)",   property_read_restrict_address_families, 0                                                         },
                 { "RestrictNamespaces",      "t",       NULL,                                    offsetof(struct security_info, restrict_namespaces)       },
                 { "RestrictRealtime",        "b",       NULL,                                    offsetof(struct security_info, restrict_realtime)         },
+                { "RestrictSUIDSGID",        "b",       NULL,                                    offsetof(struct security_info, restrict_suid_sgid)        },
                 { "RootDirectory",           "s",       NULL,                                    offsetof(struct security_info, root_directory)            },
                 { "RootImage",               "s",       NULL,                                    offsetof(struct security_info, root_image)                },
                 { "SupplementaryGroups",     "as",      NULL,                                    offsetof(struct security_info, supplementary_groups)      },