]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: add RestrictFileSystems= fragment parser
authorIago López Galeiras <iagol@microsoft.com>
Thu, 11 Feb 2021 15:59:30 +0000 (16:59 +0100)
committerIago Lopez Galeiras <iagol@microsoft.com>
Wed, 6 Oct 2021 08:52:14 +0000 (10:52 +0200)
It takes an allow or deny list of filesystems services should have
access to.

src/core/bpf-lsm.c
src/core/bpf-lsm.h
src/core/load-fragment-gperf.gperf.in
src/core/load-fragment.c
src/core/load-fragment.h
src/systemctl/systemctl-show.c
test/fuzz/fuzz-unit-file/directives.mount
test/fuzz/fuzz-unit-file/directives.service
test/fuzz/fuzz-unit-file/directives.socket
test/fuzz/fuzz-unit-file/directives.swap

index 3e480c6257f7847a3bfee7b936aca53168e065e7..46c244684946f3b8ebb64a20f57eff2ca4b49273 100644 (file)
@@ -325,3 +325,57 @@ void lsm_bpf_destroy(struct restrict_fs_bpf *prog) {
         return;
 }
 #endif
+
+int lsm_bpf_parse_filesystem(
+                const char *name,
+                Set **filesystems,
+                FilesystemParseFlags flags,
+                const char *unit,
+                const char *filename,
+                unsigned line) {
+        int r;
+
+        assert(name);
+        assert(filesystems);
+
+        if (name[0] == '@') {
+                const FilesystemSet *set;
+                const char *i;
+
+                set = filesystem_set_find(name);
+                if (!set) {
+                        log_syntax(unit, flags & FILESYSTEM_PARSE_LOG ? LOG_WARNING : LOG_DEBUG, filename, line, 0,
+                                   "Unknown filesystem group, ignoring: %s", name);
+                        return 0;
+                }
+
+                NULSTR_FOREACH(i, set->value) {
+                        /* Call ourselves again, for the group to parse. Note that we downgrade logging here (i.e. take
+                         * away the FILESYSTEM_PARSE_LOG flag) since any issues in the group table are our own problem,
+                         * not a problem in user configuration data and we shouldn't pretend otherwise by complaining
+                         * about them. */
+                        r = lsm_bpf_parse_filesystem(i, filesystems, flags &~ FILESYSTEM_PARSE_LOG, unit, filename, line);
+                        if (r < 0)
+                                return r;
+                }
+        } else {
+                /* If we previously wanted to forbid access to a filesystem and now
+                 * we want to allow it, then remove it from the list. */
+                if (!(flags & FILESYSTEM_PARSE_INVERT) == !!(flags & FILESYSTEM_PARSE_ALLOW_LIST)) {
+                        r = set_put_strdup(filesystems, name);
+                        if (r < 0)
+                                switch (r) {
+                                case -ENOMEM:
+                                        return flags & FILESYSTEM_PARSE_LOG ? log_oom() : -ENOMEM;
+                                case -EEXIST:
+                                        /* Alredy in set, ignore */
+                                        break;
+                                default:
+                                        return r;
+                                }
+                } else
+                        free(set_remove(*filesystems, name));
+        }
+
+        return 0;
+}
index 625fb32b5015af00a144c7a32eadd012b32311be..8bd58a29e53e029360f7393bdbc0dbd245a7675f 100644 (file)
@@ -3,6 +3,12 @@
 
 #include "hashmap.h"
 
+typedef enum FilesystemParseFlags {
+        FILESYSTEM_PARSE_INVERT     = 1 << 0,
+        FILESYSTEM_PARSE_ALLOW_LIST = 1 << 1,
+        FILESYSTEM_PARSE_LOG        = 1 << 2,
+} FilesystemParseFlags;
+
 typedef struct Unit Unit;
 typedef struct Manager Manager;
 
@@ -14,3 +20,9 @@ int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, bool allo
 int lsm_bpf_cleanup(const Unit *u);
 int lsm_bpf_map_restrict_fs_fd(Unit *u);
 void lsm_bpf_destroy(struct restrict_fs_bpf *prog);
+int lsm_bpf_parse_filesystem(const char *name,
+                             Set **filesystems,
+                             FilesystemParseFlags flags,
+                             const char *unit,
+                             const char *filename,
+                             unsigned line);
index 799a179430d0b33cded8e9b6e5f0e14da90d8603..480ec66bf9e59d372ebd58e74445ff0f5f0d3ca6 100644 (file)
@@ -81,6 +81,7 @@
 {{type}}.RestrictAddressFamilies,          config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
 {{type}}.LockPersonality,                  config_parse_warn_compat,                    DISABLED_CONFIGURATION,             0
 {% endif %}
+{{type}}.RestrictFileSystems,              config_parse_restrict_filesystems,           0,                                  offsetof({{type}}, exec_context)
 {{type}}.LimitCPU,                         config_parse_rlimit,                         RLIMIT_CPU,                         offsetof({{type}}, exec_context.rlimit)
 {{type}}.LimitFSIZE,                       config_parse_rlimit,                         RLIMIT_FSIZE,                       offsetof({{type}}, exec_context.rlimit)
 {{type}}.LimitDATA,                        config_parse_rlimit,                         RLIMIT_DATA,                        offsetof({{type}}, exec_context.rlimit)
index f971084c28ee6c555168ccedc948c7568367df25..10fe579aeb36ce574e55d97d16b951dadebcfdc9 100644 (file)
@@ -19,6 +19,7 @@
 #include "all-units.h"
 #include "alloc-util.h"
 #include "bpf-firewall.h"
+#include "bpf-lsm.h"
 #include "bpf-program.h"
 #include "bpf-socket-bind.h"
 #include "bus-error.h"
@@ -3597,6 +3598,76 @@ int config_parse_restrict_namespaces(
 }
 #endif
 
+int config_parse_restrict_filesystems(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+        ExecContext *c = data;
+        bool invert = false;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (isempty(rvalue)) {
+                /* Empty assignment resets the list */
+                c->restrict_filesystems = set_free(c->restrict_filesystems);
+                c->restrict_filesystems_allow_list = false;
+                return 0;
+        }
+
+        if (rvalue[0] == '~') {
+                invert = true;
+                rvalue++;
+        }
+
+        if (!c->restrict_filesystems) {
+                if (invert)
+                        /* Allow everything but the ones listed */
+                        c->restrict_filesystems_allow_list = false;
+                else
+                        /* Allow nothing but the ones listed */
+                        c->restrict_filesystems_allow_list = true;
+        }
+
+        for (const char *p = rvalue;;) {
+                _cleanup_free_ char *word = NULL;
+
+                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
+                if (r == 0)
+                        break;
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r,
+                                   "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
+                        break;
+                }
+
+                r = lsm_bpf_parse_filesystem(
+                              word,
+                              &c->restrict_filesystems,
+                              FILESYSTEM_PARSE_LOG|
+                              (invert ? FILESYSTEM_PARSE_INVERT : 0)|
+                              (c->restrict_filesystems_allow_list ? FILESYSTEM_PARSE_ALLOW_LIST : 0),
+                              unit, filename, line);
+
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 int config_parse_unit_slice(
                 const char *unit,
                 const char *filename,
@@ -6030,6 +6101,7 @@ void unit_dump_config_items(FILE *f) {
                 { config_parse_address_families,      "FAMILIES" },
                 { config_parse_restrict_namespaces,   "NAMESPACES"  },
 #endif
+                { config_parse_restrict_filesystems,  "FILESYSTEMS"  },
                 { config_parse_cpu_shares,            "SHARES" },
                 { config_parse_cg_weight,             "WEIGHT" },
                 { config_parse_memory_limit,          "LIMIT" },
index e84f9ee39107619121f7eff002d296fe3b62a761..9173f30addd7af32699a99a56fe87b2265c5d608 100644 (file)
@@ -113,6 +113,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_sec_fix_0);
 CONFIG_PARSER_PROTOTYPE(config_parse_user_group_compat);
 CONFIG_PARSER_PROTOTYPE(config_parse_user_group_strv_compat);
 CONFIG_PARSER_PROTOTYPE(config_parse_restrict_namespaces);
+CONFIG_PARSER_PROTOTYPE(config_parse_restrict_filesystems);
 CONFIG_PARSER_PROTOTYPE(config_parse_bind_paths);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_keyring_mode);
 CONFIG_PARSER_PROTOTYPE(config_parse_protect_proc);
index d008c4172abaac1f5fb0617b71b9db030c238203..9e10560f80a05af945eb300930d4d1f56ac3ec2a 100644 (file)
@@ -1023,7 +1023,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
 
                         return 1;
 
-                } else if (STR_IN_SET(name, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies", "RestrictNetworkInterfaces")) {
+                } else if (STR_IN_SET(name, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies", "RestrictNetworkInterfaces", "RestrictFileSystems")) {
                         _cleanup_strv_free_ char **l = NULL;
                         int allow_list;
 
index bdb8f95917ef467186f1b5fc7c83bcf490792d4e..a7ee579a9a3ca2cdc10edb0680127893a014c223 100644 (file)
@@ -144,6 +144,7 @@ ReadWritePaths=
 RemoveIPC=
 RestartKillSignal=
 RestrictAddressFamilies=
+RestrictFileSystems=
 RestrictNamespaces=
 RestrictNetworkInterfaces=
 RestrictRealtime=
index d9781f0492f22879c67399b534dfbb3755a05643..4615a2229ac68b78927495c0501f8a13f5a80cdc 100644 (file)
@@ -275,6 +275,7 @@ RestartKillSignal=
 RestartPreventExitStatus=
 RestartSec=
 RestrictAddressFamilies=
+RestrictFileSystems=
 RestrictNamespaces=
 RestrictNetworkInterfaces=
 RestrictRealtime=
index 04aeb476f11b4acc972c20fcd43553f34cd3922d..df641429820ef32eccdf76ea4ebbf8139a1c525b 100644 (file)
@@ -180,6 +180,7 @@ RemoveIPC=
 RemoveOnStop=
 RestartKillSignal=
 RestrictAddressFamilies=
+RestrictFileSystems=
 RestrictNamespaces=
 RestrictNetworkInterfaces=
 RestrictRealtime=
index ff54ebfc1891b560456cd52db900e6ed3f561e28..1dfdffb379dabe1401ec2fa5e7046c4e274c985a 100644 (file)
@@ -141,6 +141,7 @@ ReadWritePaths=
 RemoveIPC=
 RestartKillSignal=
 RestrictAddressFamilies=
+RestrictFileSystems=
 RestrictNamespaces=
 RestrictNetworkInterfaces=
 RestrictRealtime=