From: Lennart Poettering Date: Mon, 25 Nov 2019 15:22:45 +0000 (+0100) Subject: core: add new LogNamespace= execution setting X-Git-Tag: v245-rc1~41^2~30 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=91dd5f7cbe6f04f9ccbf35bf5c9633b985212394;p=thirdparty%2Fsystemd.git core: add new LogNamespace= execution setting --- diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 4f412649c83..9ff3f157f55 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -766,6 +766,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_ratelimit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_ratelimit_burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LogNamespace", "s", NULL, offsetof(ExecContext, log_namespace), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("AmbientCapabilities", "t", NULL, offsetof(ExecContext, capability_ambient_set), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1436,6 +1437,32 @@ int bus_exec_context_set_transient_property( return 1; + } else if (streq(name, "LogNamespace")) { + const char *n; + + r = sd_bus_message_read(message, "s", &n); + if (r < 0) + return r; + + if (!isempty(n) && !log_namespace_name_valid(n)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log namespace name not valid"); + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + + if (isempty(n)) { + c->log_namespace = mfree(c->log_namespace); + unit_write_settingf(u, flags, name, "%s=", name); + } else { + r = free_and_strdup(&c->log_namespace, n); + if (r < 0) + return r; + + unit_write_settingf(u, flags, name, "%s=%s", name, n); + } + } + + return 1; + } else if (streq(name, "LogExtraFields")) { size_t n = 0; diff --git a/src/core/execute.c b/src/core/execute.c index b6a4f5479b8..27777c0d859 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -265,15 +265,27 @@ static int open_null_as(int flags, int nfd) { return move_fd(fd, nfd, false); } -static int connect_journal_socket(int fd, uid_t uid, gid_t gid) { - static const union sockaddr_union sa = { +static int connect_journal_socket( + int fd, + const char *log_namespace, + uid_t uid, + gid_t gid) { + + union sockaddr_union sa = { .un.sun_family = AF_UNIX, - .un.sun_path = "/run/systemd/journal/stdout", }; uid_t olduid = UID_INVALID; gid_t oldgid = GID_INVALID; + const char *j; int r; + j = log_namespace ? + strjoina("/run/systemd/journal.", log_namespace, "/stdout") : + "/run/systemd/journal/stdout"; + r = sockaddr_un_set_path(&sa.un, j); + if (r < 0) + return r; + if (gid_is_valid(gid)) { oldgid = getgid(); @@ -328,7 +340,7 @@ static int connect_logger_as( if (fd < 0) return -errno; - r = connect_journal_socket(fd, uid, gid); + r = connect_journal_socket(fd, context->log_namespace, uid, gid); if (r < 0) return r; @@ -1686,7 +1698,7 @@ static int build_environment( assert(p); assert(ret); - our_env = new0(char*, 14 + _EXEC_DIRECTORY_TYPE_MAX); + our_env = new0(char*, 15 + _EXEC_DIRECTORY_TYPE_MAX); if (!our_env) return -ENOMEM; @@ -1795,6 +1807,14 @@ static int build_environment( our_env[n_env++] = x; } + if (c->log_namespace) { + x = strjoin("LOG_NAMESPACE=", c->log_namespace); + if (!x) + return -ENOMEM; + + our_env[n_env++] = x; + } + for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) { _cleanup_free_ char *pre = NULL, *joined = NULL; const char *n; @@ -1919,6 +1939,9 @@ static bool exec_needs_mount_namespace( !strv_isempty(context->directories[EXEC_DIRECTORY_LOGS].paths))) return true; + if (context->log_namespace) + return true; + return false; } @@ -2517,6 +2540,9 @@ static bool insist_on_sandboxing( if (!path_equal(bind_mounts[i].source, bind_mounts[i].destination)) return true; + if (context->log_namespace) + return true; + return false; } @@ -2600,6 +2626,7 @@ static int apply_mount_namespace( context->n_temporary_filesystems, tmp, var, + context->log_namespace, needs_sandboxing ? context->protect_home : PROTECT_HOME_NO, needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO, context->mount_flags, @@ -4140,6 +4167,8 @@ void exec_context_done(ExecContext *c) { c->stdin_data_size = 0; c->network_namespace_path = mfree(c->network_namespace_path); + + c->log_namespace = mfree(c->log_namespace); } int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) { @@ -4675,6 +4704,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { } } + if (c->log_namespace) + fprintf(f, "%sLogNamespace: %s\n", prefix, c->log_namespace); + if (c->secure_bits) { _cleanup_free_ char *str = NULL; diff --git a/src/core/execute.h b/src/core/execute.h index 5aacac4a40e..09c1510aafd 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -250,6 +250,8 @@ struct ExecContext { int log_level_max; + char *log_namespace; + bool private_tmp; bool private_network; bool private_devices; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 9e622597bee..69abdb65ba7 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -119,6 +119,7 @@ $1.ProtectKernelLogs, config_parse_bool, 0, $1.ProtectClock, config_parse_bool, 0, offsetof($1, exec_context.protect_clock) $1.ProtectControlGroups, config_parse_bool, 0, offsetof($1, exec_context.protect_control_groups) $1.NetworkNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.network_namespace_path) +$1.LogNamespace, config_parse_log_namespace, 0, offsetof($1, exec_context) $1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) $1.PrivateUsers, config_parse_bool, 0, offsetof($1, exec_context.private_users) $1.PrivateMounts, config_parse_bool, 0, offsetof($1, exec_context.private_mounts) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 379be9c96b6..71a9873da46 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -52,10 +52,11 @@ #include "stat-util.h" #include "string-util.h" #include "strv.h" +#include "syslog-util.h" +#include "time-util.h" #include "unit-name.h" #include "unit-printf.h" #include "user-util.h" -#include "time-util.h" #include "web-util.h" static int parse_socket_protocol(const char *s) { @@ -2519,6 +2520,48 @@ int config_parse_log_extra_fields( } } +int config_parse_log_namespace( + 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) { + + _cleanup_free_ char *k = NULL; + ExecContext *c = data; + const Unit *u = userdata; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(c); + + if (isempty(rvalue)) { + c->log_namespace = mfree(c->log_namespace); + return 0; + } + + r = unit_full_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue); + return 0; + } + + if (!log_namespace_name_valid(k)) { + log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Specified log namespace name is not valid: %s", k); + return 0; + } + + free_and_replace(c->log_namespace, k); + return 0; +} + int config_parse_unit_condition_path( const char *unit, const char *filename, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 28613ef5b38..b6b46b2449b 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -107,6 +107,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_keyring_mode); CONFIG_PARSER_PROTOTYPE(config_parse_job_timeout_sec); CONFIG_PARSER_PROTOTYPE(config_parse_job_running_timeout_sec); CONFIG_PARSER_PROTOTYPE(config_parse_log_extra_fields); +CONFIG_PARSER_PROTOTYPE(config_parse_log_namespace); CONFIG_PARSER_PROTOTYPE(config_parse_collect_mode); CONFIG_PARSER_PROTOTYPE(config_parse_pid_file); CONFIG_PARSER_PROTOTYPE(config_parse_exit_status); diff --git a/src/core/namespace.c b/src/core/namespace.c index f121cb7ca41..77854058304 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1132,6 +1132,7 @@ static size_t namespace_calculate_mounts( size_t n_temporary_filesystems, const char* tmp_dir, const char* var_tmp_dir, + const char* log_namespace, ProtectHome protect_home, ProtectSystem protect_system) { @@ -1166,7 +1167,8 @@ static size_t namespace_calculate_mounts( (ns_info->protect_control_groups ? 1 : 0) + protect_home_cnt + protect_system_cnt + (ns_info->protect_hostname ? 2 : 0) + - (namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0); + (namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0) + + !!log_namespace; } static void normalize_mounts(const char *root_directory, MountEntry *mounts, size_t *n_mounts) { @@ -1247,6 +1249,7 @@ int setup_namespace( size_t n_temporary_filesystems, const char* tmp_dir, const char* var_tmp_dir, + const char *log_namespace, ProtectHome protect_home, ProtectSystem protect_system, unsigned long mount_flags, @@ -1323,6 +1326,7 @@ int setup_namespace( n_bind_mounts, n_temporary_filesystems, tmp_dir, var_tmp_dir, + log_namespace, protect_home, protect_system); if (n_mounts > 0) { @@ -1428,6 +1432,23 @@ int setup_namespace( }; } + if (log_namespace) { + _cleanup_free_ char *q; + + q = strjoin("/run/systemd/journal.", log_namespace); + if (!q) { + r = -ENOMEM; + goto finish; + } + + *(m++) = (MountEntry) { + .path_const = "/run/systemd/journal", + .mode = BIND_MOUNT_RECURSIVE, + .read_only = true, + .source_malloc = TAKE_PTR(q), + }; + } + assert(mounts + n_mounts == m); /* Prepend the root directory where that's necessary */ diff --git a/src/core/namespace.h b/src/core/namespace.h index 60a6abcd45e..ef6c9bdc9bd 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -84,6 +84,7 @@ int setup_namespace( size_t n_temporary_filesystems, const char *tmp_dir, const char *var_tmp_dir, + const char *log_namespace, ProtectHome protect_home, ProtectSystem protect_system, unsigned long mount_flags, diff --git a/src/core/unit.c b/src/core/unit.c index 8570eaefb4c..40897023355 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1059,13 +1059,25 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { !IN_SET(c->std_error, EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE, - EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE)) + EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) && + !c->log_namespace) return 0; - /* If syslog or kernel logging is requested, make sure our own - * logging daemon is run first. */ + /* If syslog or kernel logging is requested (or log namespacing is), make sure our own logging daemon + * is run first. */ + + if (c->log_namespace) { + _cleanup_free_ char *socket_unit = NULL; + + r = unit_name_build_from_type("systemd-journald", c->log_namespace, UNIT_SOCKET, &socket_unit); + if (r < 0) + return r; - r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE); + r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, socket_unit, true, UNIT_DEPENDENCY_FILE); + if (r < 0) + return r; + } else + r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE); if (r < 0) return r; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 254007ef116..28d85944a8a 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -833,7 +833,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "RuntimeDirectoryPreserve", "Personality", "KeyringMode", - "NetworkNamespacePath")) + "NetworkNamespacePath", + "LogNamespace")) return bus_append_string(m, field, eq); if (STR_IN_SET(field, "IgnoreSIGPIPE", diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 41ea733b7eb..f2bfc6c62bc 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -148,6 +148,7 @@ static void test_protect_kernel_logs(void) { NULL, 0, NULL, NULL, + NULL, PROTECT_HOME_NO, PROTECT_SYSTEM_NO, 0, diff --git a/src/test/test-ns.c b/src/test/test-ns.c index e9233a16437..48a5ff9f2d3 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -72,6 +72,7 @@ int main(int argc, char *argv[]) { &(TemporaryFileSystem) { .path = (char*) "/var", .options = (char*) "ro" }, 1, tmp_dir, var_tmp_dir, + NULL, PROTECT_HOME_NO, PROTECT_SYSTEM_NO, 0,