core: add new LogNamespace= execution setting
This commit is contained in:
parent
839d1b2014
commit
91dd5f7cbe
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -250,6 +250,8 @@ struct ExecContext {
|
|||
|
||||
int log_level_max;
|
||||
|
||||
char *log_namespace;
|
||||
|
||||
bool private_tmp;
|
||||
bool private_network;
|
||||
bool private_devices;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -148,6 +148,7 @@ static void test_protect_kernel_logs(void) {
|
|||
NULL, 0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
PROTECT_HOME_NO,
|
||||
PROTECT_SYSTEM_NO,
|
||||
0,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue