]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: add new LogNamespace= execution setting
authorLennart Poettering <lennart@poettering.net>
Mon, 25 Nov 2019 15:22:45 +0000 (16:22 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 31 Jan 2020 14:01:43 +0000 (15:01 +0100)
12 files changed:
src/core/dbus-execute.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/namespace.c
src/core/namespace.h
src/core/unit.c
src/shared/bus-unit-util.c
src/test/test-namespace.c
src/test/test-ns.c

index 4f412649c836dd3f6601495777a1664d1da41ab2..9ff3f157f556d8fa0a7982104eb6999f69c49d96 100644 (file)
@@ -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;
 
index b6a4f5479b8c8525aefebf7c82684d3b1e091c3d..27777c0d85952d1d97c8a42a242c8939933f0eaa 100644 (file)
@@ -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;
 
index 5aacac4a40e710445950f81d04c5aeac24e89697..09c1510aafd3b9c28680036451251740830ceab1 100644 (file)
@@ -250,6 +250,8 @@ struct ExecContext {
 
         int log_level_max;
 
+        char *log_namespace;
+
         bool private_tmp;
         bool private_network;
         bool private_devices;
index 9e622597bee0c57e24de58674faa6120b4b24fd8..69abdb65ba704d018e37e8aa6afc32bf20ac6898 100644 (file)
@@ -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)
index 379be9c96b65d2435436ff468a944e33c9c9a7d3..71a9873da46fbe6404c967b32982c031de02a9cd 100644 (file)
 #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,
index 28613ef5b38f8b7e8dfb7f101171cefb8a9475c0..b6b46b2449b118f6cad5876de780871991c1e250 100644 (file)
@@ -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);
index f121cb7ca412389f9d21535e77bc23669d632337..77854058304120c5ae617397a9dab6eb3eac4881 100644 (file)
@@ -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 */
index 60a6abcd45e2573481a95c33e43ce071a4f6b60d..ef6c9bdc9bdcaa8bb3c68b93ff4e6ee42164d1ef 100644 (file)
@@ -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,
index 8570eaefb4cd380a6ebb82dde81e7001c4e7d42b..408970233551b576314527af1430c89fe6b4eee0 100644 (file)
@@ -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;
 
index 254007ef116e002ebdda0d51e5458079532f9cd6..28d85944a8a73b0b3500d98ed90a7b135de13204 100644 (file)
@@ -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",
index 41ea733b7eb2911e4fd414922a5a98523fb391d4..f2bfc6c62bc9c3f5724e725549cb2932a1bee767 100644 (file)
@@ -148,6 +148,7 @@ static void test_protect_kernel_logs(void) {
                                     NULL, 0,
                                     NULL,
                                     NULL,
+                                    NULL,
                                     PROTECT_HOME_NO,
                                     PROTECT_SYSTEM_NO,
                                     0,
index e9233a16437e23268ec15d3a5e41ad30ee60acb0..48a5ff9f2d331738ddffa1ae0293920b013bc3b2 100644 (file)
@@ -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,