From: Lennart Poettering Date: Wed, 4 Jun 2014 16:07:55 +0000 (+0200) Subject: core: rename ReadOnlySystem= to ProtectSystem= and add a third value for also mountin... X-Git-Tag: v214~79 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=1b8689f94983b47bf190e77ddb03a8fc6af15fb3 core: rename ReadOnlySystem= to ProtectSystem= and add a third value for also mounting /etc read-only Also, rename ProtectedHome= to ProtectHome=, to simplify things a bit. With this in place we now have two neat options ProtectSystem= and ProtectHome= for protecting the OS itself (and optionally its configuration), and for protecting the user's data. --- diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 366430349..d426ac089 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -935,16 +935,21 @@ - ReadOnlySystem= + ProtectSystem= Takes a boolean - argument. If true, mounts the - /usr and - /boot directories - read-only for processes invoked by - this unit. This setting ensures that - any modification of the vendor - supplied operating system is + argument or + full. If true, + mounts the /usr + and /boot + directories read-only for processes + invoked by this unit. If set to + full the + /etc is mounted + read-only, too. This setting ensures + that any modification of the vendor + supplied operating system (and + optionally its configuration) is prohibited for the service. It is recommended to enable this setting for all long-running services, unless they @@ -962,7 +967,7 @@ - ProtectedHome= + ProtectHome= Takes a boolean argument or @@ -977,7 +982,7 @@ instead. It is recommended to enable this setting for all long-running services (in particular network-facing - one), to ensure they cannot get access + ones), to ensure they cannot get access to private user data, unless the services actually require access to the user's private data. Note however, diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 2aa08c143..cb9a077d0 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -45,7 +45,8 @@ BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutp static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput); -static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protected_home, protected_home, ProtectedHome); +static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_home, protect_home, ProtectHome); +static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_system, protect_system, ProtectSystem); static int property_get_environment_files( sd_bus *bus, @@ -629,8 +630,8 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ProtectedHome", "s", bus_property_get_protected_home, offsetof(ExecContext, protected_home), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ReadOnlySystem", "b", bus_property_get_bool, offsetof(ExecContext, read_only_system), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ProtectHome", "s", bus_property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ProtectSystem", "s", bus_property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/execute.c b/src/core/execute.c index ce8b9bcb8..78fb81f72 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1570,8 +1570,8 @@ int exec_spawn(ExecCommand *command, context->mount_flags != 0 || (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) || context->private_devices || - context->read_only_system || - context->protected_home != PROTECTED_HOME_NO) { + context->protect_system != PROTECT_SYSTEM_NO || + context->protect_home != PROTECT_HOME_NO) { char *tmp = NULL, *var = NULL; @@ -1595,8 +1595,8 @@ int exec_spawn(ExecCommand *command, tmp, var, context->private_devices, - context->protected_home, - context->read_only_system, + context->protect_home, + context->protect_system, context->mount_flags); if (err < 0) { r = EXIT_NAMESPACE; @@ -2114,8 +2114,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { "%sPrivateTmp: %s\n" "%sPrivateNetwork: %s\n" "%sPrivateDevices: %s\n" - "%sProtectedHome: %s\n" - "%sReadOnlySystem: %s\n" + "%sProtectHome: %s\n" + "%sProtectSystem: %s\n" "%sIgnoreSIGPIPE: %s\n", prefix, c->umask, prefix, c->working_directory ? c->working_directory : "/", @@ -2124,8 +2124,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, yes_no(c->private_tmp), prefix, yes_no(c->private_network), prefix, yes_no(c->private_devices), - prefix, protected_home_to_string(c->protected_home), - prefix, yes_no(c->read_only_system), + prefix, protect_home_to_string(c->protect_home), + prefix, protect_system_to_string(c->protect_system), prefix, yes_no(c->ignore_sigpipe)); STRV_FOREACH(e, c->environment) diff --git a/src/core/execute.h b/src/core/execute.h index 3d6f77c8e..9d05d3a9d 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -157,8 +157,8 @@ struct ExecContext { bool private_tmp; bool private_network; bool private_devices; - bool read_only_system; - ProtectedHome protected_home; + ProtectSystem protect_system; + ProtectHome protect_home; bool no_new_privileges; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 95f59f55d..089c32a81 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -80,8 +80,8 @@ $1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, $1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp) $1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) $1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices) -$1.ReadOnlySystem, config_parse_bool, 0, offsetof($1, exec_context.read_only_system) -$1.ProtectedHome, config_parse_protected_home, 0, offsetof($1, exec_context) +$1.ProtectSystem, config_parse_protect_system, 0, offsetof($1, exec_context.protect_system) +$1.ProtectHome, config_parse_protect_home, 0, offsetof($1, exec_context.protect_home) $1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context) $1.Personality, config_parse_personality, 0, offsetof($1, exec_context.personality) $1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.runtime_directory_mode) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 64d4c2f63..54d3af1a9 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3101,7 +3101,7 @@ int config_parse_no_new_privileges( return 0; } -int config_parse_protected_home( +int config_parse_protect_home( const char* unit, const char *filename, unsigned line, @@ -3126,19 +3126,62 @@ int config_parse_protected_home( k = parse_boolean(rvalue); if (k > 0) - c->protected_home = PROTECTED_HOME_YES; + c->protect_home = PROTECT_HOME_YES; else if (k == 0) - c->protected_home = PROTECTED_HOME_NO; + c->protect_home = PROTECT_HOME_NO; else { - ProtectedHome h; + ProtectHome h; - h = protected_home_from_string(rvalue); + h = protect_home_from_string(rvalue); if (h < 0){ - log_syntax(unit, LOG_ERR, filename, line, -h, "Failed to parse protected home value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, -h, "Failed to parse protect home value, ignoring: %s", rvalue); return 0; } - c->protected_home = h; + c->protect_home = h; + } + + return 0; +} + +int config_parse_protect_system( + 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; + int k; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + /* Our enum shall be a superset of booleans, hence first try + * to parse as as boolean, and then as enum */ + + k = parse_boolean(rvalue); + if (k > 0) + c->protect_system = PROTECT_SYSTEM_YES; + else if (k == 0) + c->protect_system = PROTECT_SYSTEM_NO; + else { + ProtectSystem s; + + s = protect_system_from_string(rvalue); + if (s < 0){ + log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse protect system value, ignoring: %s", rvalue); + return 0; + } + + c->protect_system = s; } return 0; diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 9e4494cf9..1c21c466d 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -98,7 +98,8 @@ int config_parse_set_status(const char *unit, const char *filename, unsigned lin int config_parse_namespace_path_strv(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); int config_parse_no_new_privileges(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); int config_parse_cpu_quota(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); -int config_parse_protected_home(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); +int config_parse_protect_home(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); +int config_parse_protect_system(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); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/core/namespace.c b/src/core/namespace.c index 1f987a4b9..080c086fd 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -337,8 +337,8 @@ int setup_namespace( char* tmp_dir, char* var_tmp_dir, bool private_dev, - ProtectedHome protected_home, - bool read_only_system, + ProtectHome protect_home, + ProtectSystem protect_system, unsigned mount_flags) { BindMount *m, *mounts = NULL; @@ -356,8 +356,9 @@ int setup_namespace( strv_length(read_only_dirs) + strv_length(inaccessible_dirs) + private_dev + - (protected_home != PROTECTED_HOME_NO ? 2 : 0) + - (read_only_system ? 2 : 0); + (protect_home != PROTECT_HOME_NO ? 2 : 0) + + (protect_system != PROTECT_SYSTEM_NO ? 2 : 0) + + (protect_system == PROTECT_SYSTEM_FULL ? 1 : 0); if (n > 0) { m = mounts = (BindMount *) alloca(n * sizeof(BindMount)); @@ -391,14 +392,14 @@ int setup_namespace( m++; } - if (protected_home != PROTECTED_HOME_NO) { - r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user"), protected_home == PROTECTED_HOME_READ_ONLY ? READONLY : INACCESSIBLE); + if (protect_home != PROTECT_HOME_NO) { + r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user"), protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE); if (r < 0) return r; } - if (read_only_system) { - r = append_mounts(&m, STRV_MAKE("/usr", "-/boot"), READONLY); + if (protect_system != PROTECT_SYSTEM_NO) { + r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL ? STRV_MAKE("/usr", "/etc", "-/boot") : STRV_MAKE("/usr", "-/boot"), READONLY); if (r < 0) return r; } @@ -604,10 +605,18 @@ fail: return r; } -static const char *const protected_home_table[_PROTECTED_HOME_MAX] = { - [PROTECTED_HOME_NO] = "no", - [PROTECTED_HOME_YES] = "yes", - [PROTECTED_HOME_READ_ONLY] = "read-only", +static const char *const protect_home_table[_PROTECT_HOME_MAX] = { + [PROTECT_HOME_NO] = "no", + [PROTECT_HOME_YES] = "yes", + [PROTECT_HOME_READ_ONLY] = "read-only", }; -DEFINE_STRING_TABLE_LOOKUP(protected_home, ProtectedHome); +DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome); + +static const char *const protect_system_table[_PROTECT_SYSTEM_MAX] = { + [PROTECT_SYSTEM_NO] = "no", + [PROTECT_SYSTEM_YES] = "yes", + [PROTECT_SYSTEM_FULL] = "full", +}; + +DEFINE_STRING_TABLE_LOOKUP(protect_system, ProtectSystem); diff --git a/src/core/namespace.h b/src/core/namespace.h index b985bdf51..9343fe326 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -25,13 +25,21 @@ #include "macro.h" -typedef enum ProtectedHome { - PROTECTED_HOME_NO, - PROTECTED_HOME_YES, - PROTECTED_HOME_READ_ONLY, - _PROTECTED_HOME_MAX, - _PROTECTED_HOME_INVALID = -1 -} ProtectedHome; +typedef enum ProtectHome { + PROTECT_HOME_NO, + PROTECT_HOME_YES, + PROTECT_HOME_READ_ONLY, + _PROTECT_HOME_MAX, + _PROTECT_HOME_INVALID = -1 +} ProtectHome; + +typedef enum ProtectSystem { + PROTECT_SYSTEM_NO, + PROTECT_SYSTEM_YES, + PROTECT_SYSTEM_FULL, + _PROTECT_SYSTEM_MAX, + _PROTECT_SYSTEM_INVALID = -1 +} ProtectSystem; int setup_namespace(char **read_write_dirs, char **read_only_dirs, @@ -39,8 +47,8 @@ int setup_namespace(char **read_write_dirs, char *tmp_dir, char *var_tmp_dir, bool private_dev, - ProtectedHome protected_home, - bool read_only_system, + ProtectHome protect_home, + ProtectSystem protect_system, unsigned mount_flags); int setup_tmp_dirs(const char *id, @@ -49,5 +57,8 @@ int setup_tmp_dirs(const char *id, int setup_netns(int netns_storage_socket[2]); -const char* protected_home_to_string(ProtectedHome p) _const_; -ProtectedHome protected_home_from_string(const char *s) _pure_; +const char* protect_home_to_string(ProtectHome p) _const_; +ProtectHome protect_home_from_string(const char *s) _pure_; + +const char* protect_system_to_string(ProtectSystem p) _const_; +ProtectSystem protect_system_from_string(const char *s) _pure_; diff --git a/src/test/test-ns.c b/src/test/test-ns.c index 71581934c..acad72589 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -60,8 +60,8 @@ int main(int argc, char *argv[]) { tmp_dir, var_tmp_dir, true, - PROTECTED_HOME_NO, - false, + PROTECT_HOME_NO, + PROTECT_SYSTEM_NO, 0); if (r < 0) { log_error("Failed to setup namespace: %s", strerror(-r)); diff --git a/units/systemd-bus-proxyd@.service.in b/units/systemd-bus-proxyd@.service.in index 3dc2cd9e6..0499269f3 100644 --- a/units/systemd-bus-proxyd@.service.in +++ b/units/systemd-bus-proxyd@.service.in @@ -18,5 +18,5 @@ CapabilityBoundingSet=CAP_IPC_OWNER CAP_SETUID CAP_SETGID CAP_SETPCAP PrivateTmp=yes PrivateDevices=yes PrivateNetwork=yes -ReadOnlySystem=yes -ProtectedHome=yes +ProtectSystem=full +ProtectHome=yes diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in index 497b8d997..cc88ecd0d 100644 --- a/units/systemd-hostnamed.service.in +++ b/units/systemd-hostnamed.service.in @@ -18,5 +18,5 @@ WatchdogSec=1min PrivateTmp=yes PrivateDevices=yes PrivateNetwork=yes -ReadOnlySystem=yes -ProtectedHome=yes +ProtectSystem=yes +ProtectHome=yes diff --git a/units/systemd-journal-gatewayd.service.in b/units/systemd-journal-gatewayd.service.in index 3695240cb..5bd8e4b34 100644 --- a/units/systemd-journal-gatewayd.service.in +++ b/units/systemd-journal-gatewayd.service.in @@ -17,8 +17,8 @@ SupplementaryGroups=systemd-journal PrivateTmp=yes PrivateDevices=yes PrivateNetwork=yes -ReadOnlySystem=yes -ProtectedHome=yes +ProtectSystem=full +ProtectHome=yes [Install] Also=systemd-journal-gatewayd.socket diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in index 4a307c708..70139795a 100644 --- a/units/systemd-journald.service.in +++ b/units/systemd-journald.service.in @@ -21,8 +21,6 @@ RestartSec=0 NotifyAccess=all StandardOutput=null CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID -ReadOnlySystem=yes -ProtectedHome=yes WatchdogSec=1min # Increase the default a bit in order to allow many simultaneous diff --git a/units/systemd-localed.service.in b/units/systemd-localed.service.in index e1792d654..bfa097844 100644 --- a/units/systemd-localed.service.in +++ b/units/systemd-localed.service.in @@ -18,5 +18,5 @@ WatchdogSec=1min PrivateTmp=yes PrivateDevices=yes PrivateNetwork=yes -ReadOnlySystem=yes -ProtectedHome=yes +ProtectSystem=yes +ProtectHome=yes diff --git a/units/systemd-machined.service.in b/units/systemd-machined.service.in index 07522e12a..e60ea32fa 100644 --- a/units/systemd-machined.service.in +++ b/units/systemd-machined.service.in @@ -20,5 +20,5 @@ WatchdogSec=1min PrivateTmp=yes PrivateDevices=yes PrivateNetwork=yes -ReadOnlySystem=yes -ProtectedHome=yes +PortectSystem=full +ProtectHome=yes diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in index a92899920..373ac4e0f 100644 --- a/units/systemd-networkd.service.in +++ b/units/systemd-networkd.service.in @@ -20,8 +20,8 @@ Restart=always RestartSec=0 ExecStart=@rootlibexecdir@/systemd-networkd CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER -ReadOnlySystem=yes -ProtectedHome=yes +ProtectSystem=full +ProtectHome=yes WatchdogSec=1min [Install] diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.in index 787fde2c4..013362162 100644 --- a/units/systemd-resolved.service.in +++ b/units/systemd-resolved.service.in @@ -16,8 +16,8 @@ Restart=always RestartSec=0 ExecStart=@rootlibexecdir@/systemd-resolved CapabilityBoundingSet=CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER -ReadOnlySystem=yes -ProtectedHome=yes +ProtectSystem=full +ProtectHome=yes [Install] WantedBy=multi-user.target diff --git a/units/systemd-timedated.service.in b/units/systemd-timedated.service.in index 9658149ee..fe5ccb460 100644 --- a/units/systemd-timedated.service.in +++ b/units/systemd-timedated.service.in @@ -16,5 +16,5 @@ BusName=org.freedesktop.timedate1 CapabilityBoundingSet=CAP_SYS_TIME WatchdogSec=1min PrivateTmp=yes -ReadOnlySystem=yes -ProtectedHome=yes +ProtectSystem=yes +ProtectHome=yes diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in index 030e4a042..8d898e2fa 100644 --- a/units/systemd-timesyncd.service.in +++ b/units/systemd-timesyncd.service.in @@ -23,8 +23,8 @@ ExecStart=@rootlibexecdir@/systemd-timesyncd CapabilityBoundingSet=CAP_SYS_TIME CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER PrivateTmp=yes PrivateDevices=yes -ReadOnlySystem=yes -ProtectedHome=yes +ProtectSystem=full +ProtectHome=yes WatchdogSec=1min [Install]