core: add new LogNamespace= execution setting

This commit is contained in:
Lennart Poettering 2019-11-25 16:22:45 +01:00
parent 839d1b2014
commit 91dd5f7cbe
12 changed files with 155 additions and 12 deletions

View 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;

View 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;

View file

@ -250,6 +250,8 @@ struct ExecContext {
int log_level_max;
char *log_namespace;
bool private_tmp;
bool private_network;
bool private_devices;

View 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)

View file

@ -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,

View 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);

View 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 */

View 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,

View 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. */
r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE);
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_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;

View 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",

View file

@ -148,6 +148,7 @@ static void test_protect_kernel_logs(void) {
NULL, 0,
NULL,
NULL,
NULL,
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,

View 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,