New directives PrivateIPC and IPCNamespacePath

This commit is contained in:
Xℹ Ruoyao
2021-03-04 00:04:36 +08:00
parent 54c2459d56
commit a70581ffb5
11 changed files with 270 additions and 23 deletions
+8
View File
@@ -1162,6 +1162,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateMounts", "b", bus_property_get_bool, offsetof(ExecContext, private_mounts), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateIPC", "b", bus_property_get_bool, offsetof(ExecContext, private_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectHome", "s", property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectSystem", "s", 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),
@@ -1204,6 +1205,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("ProcSubset", "s", property_get_proc_subset, offsetof(ExecContext, proc_subset), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IPCNamespacePath", "s", NULL, offsetof(ExecContext, ipc_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
/* Obsolete/redundant properties: */
SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
@@ -1753,6 +1755,9 @@ int bus_exec_context_set_transient_property(
if (streq(name, "PrivateNetwork"))
return bus_set_transient_bool(u, name, &c->private_network, message, flags, error);
if (streq(name, "PrivateIPC"))
return bus_set_transient_bool(u, name, &c->private_ipc, message, flags, error);
if (streq(name, "PrivateUsers"))
return bus_set_transient_bool(u, name, &c->private_users, message, flags, error);
@@ -1873,6 +1878,9 @@ int bus_exec_context_set_transient_property(
if (streq(name, "NetworkNamespacePath"))
return bus_set_transient_path(u, name, &c->network_namespace_path, message, flags, error);
if (streq(name, "IPCNamespacePath"))
return bus_set_transient_path(u, name, &c->ipc_namespace_path, message, flags, error);
if (streq(name, "SupplementaryGroups")) {
_cleanup_strv_free_ char **l = NULL;
char **p;
+139 -16
View File
@@ -3476,8 +3476,10 @@ static int close_remaining_fds(
n_dont_close += n_fds;
}
if (runtime)
if (runtime) {
append_socket_pair(dont_close, &n_dont_close, runtime->netns_storage_socket);
append_socket_pair(dont_close, &n_dont_close, runtime->ipcns_storage_socket);
}
if (dcreds) {
if (dcreds->user)
@@ -3925,6 +3927,14 @@ static int exec_child(
}
}
if (context->ipc_namespace_path && runtime && runtime->ipcns_storage_socket[0] >= 0) {
r = open_shareable_ns_path(runtime->ipcns_storage_socket, context->ipc_namespace_path, CLONE_NEWIPC);
if (r < 0) {
*exit_status = EXIT_NAMESPACE;
return log_unit_error_errno(unit, r, "Failed to open IPC namespace path %s: %m", context->ipc_namespace_path);
}
}
r = setup_input(context, params, socket_fd, named_iofds);
if (r < 0) {
*exit_status = EXIT_STDIN;
@@ -4211,6 +4221,25 @@ static int exec_child(
log_unit_warning(unit, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring.");
}
if ((context->private_ipc || context->ipc_namespace_path) && runtime && runtime->ipcns_storage_socket[0] >= 0) {
if (ns_type_supported(NAMESPACE_IPC)) {
r = setup_shareable_ns(runtime->ipcns_storage_socket, CLONE_NEWIPC);
if (r == -EPERM)
log_unit_warning_errno(unit, r,
"PrivateIPC=yes is configured, but IPC namespace setup failed, ignoring: %m");
else if (r < 0) {
*exit_status = EXIT_NAMESPACE;
return log_unit_error_errno(unit, r, "Failed to set up IPC namespacing: %m");
}
} else if (context->ipc_namespace_path) {
*exit_status = EXIT_NAMESPACE;
return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EOPNOTSUPP),
"IPCNamespacePath= is not supported, refusing.");
} else
log_unit_warning(unit, "PrivateIPC=yes is configured, but the kernel does not support IPC namespaces, ignoring.");
}
needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
if (needs_mount_namespace) {
_cleanup_free_ char *error_path = NULL;
@@ -4314,7 +4343,7 @@ static int exec_child(
#endif
/* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are
* more aggressive this time since socket_fd and the netns fds we don't need anymore. We do keep the exec_fd
* more aggressive this time since socket_fd and the netns and ipcns fds we don't need anymore. We do keep the exec_fd
* however if we have it as we want to keep it open until the final execve(). */
r = close_all_fds(keep_fds, n_keep_fds);
@@ -6057,6 +6086,7 @@ static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
rt->tmp_dir = mfree(rt->tmp_dir);
rt->var_tmp_dir = mfree(rt->var_tmp_dir);
safe_close_pair(rt->netns_storage_socket);
safe_close_pair(rt->ipcns_storage_socket);
return mfree(rt);
}
@@ -6081,6 +6111,7 @@ static int exec_runtime_allocate(ExecRuntime **ret, const char *id) {
*n = (ExecRuntime) {
.id = TAKE_PTR(id_copy),
.netns_storage_socket = { -1, -1 },
.ipcns_storage_socket = { -1, -1 },
};
*ret = n;
@@ -6093,6 +6124,7 @@ static int exec_runtime_add(
char **tmp_dir,
char **var_tmp_dir,
int netns_storage_socket[2],
int ipcns_storage_socket[2],
ExecRuntime **ret) {
_cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
@@ -6101,7 +6133,7 @@ static int exec_runtime_add(
assert(m);
assert(id);
/* tmp_dir, var_tmp_dir, netns_storage_socket fds are donated on success */
/* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
r = exec_runtime_allocate(&rt, id);
if (r < 0)
@@ -6120,6 +6152,11 @@ static int exec_runtime_add(
rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
}
if (ipcns_storage_socket) {
rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
}
rt->manager = m;
if (ret)
@@ -6136,7 +6173,7 @@ static int exec_runtime_make(
ExecRuntime **ret) {
_cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
_cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 };
_cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 }, ipcns_storage_socket[2] = { -1, -1 };
int r;
assert(m);
@@ -6144,7 +6181,7 @@ static int exec_runtime_make(
assert(id);
/* It is not necessary to create ExecRuntime object. */
if (!c->private_network && !c->private_tmp && !c->network_namespace_path) {
if (!c->private_network && !c->private_ipc && !c->private_tmp && !c->network_namespace_path) {
*ret = NULL;
return 0;
}
@@ -6163,7 +6200,12 @@ static int exec_runtime_make(
return -errno;
}
r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ret);
if (c->private_ipc || c->ipc_namespace_path) {
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
return -errno;
}
r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
if (r < 0)
return r;
@@ -6254,6 +6296,26 @@ int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
fprintf(f, " netns-socket-1=%i", copy);
}
if (rt->ipcns_storage_socket[0] >= 0) {
int copy;
copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
if (copy < 0)
return copy;
fprintf(f, " ipcns-socket-0=%i", copy);
}
if (rt->ipcns_storage_socket[1] >= 0) {
int copy;
copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
if (copy < 0)
return copy;
fprintf(f, " ipcns-socket-1=%i", copy);
}
fputc('\n', f);
}
@@ -6335,6 +6397,28 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
safe_close(rt->netns_storage_socket[1]);
rt->netns_storage_socket[1] = fdset_remove(fds, fd);
} else if (streq(key, "ipcns-socket-0")) {
int fd;
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
return 0;
}
safe_close(rt->ipcns_storage_socket[0]);
rt->ipcns_storage_socket[0] = fdset_remove(fds, fd);
} else if (streq(key, "ipcns-socket-1")) {
int fd;
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
return 0;
}
safe_close(rt->ipcns_storage_socket[1]);
rt->ipcns_storage_socket[1] = fdset_remove(fds, fd);
} else
return 0;
@@ -6358,7 +6442,7 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
_cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
char *id = NULL;
int r, fdpair[] = {-1, -1};
int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
const char *p, *v = value;
size_t n;
@@ -6401,13 +6485,13 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
n = strcspn(v, " ");
buf = strndupa(v, n);
r = safe_atoi(buf, &fdpair[0]);
r = safe_atoi(buf, &netns_fdpair[0]);
if (r < 0)
return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-0=%s: %m", buf);
if (!fdset_contains(fds, fdpair[0]))
if (!fdset_contains(fds, netns_fdpair[0]))
return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
"exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", fdpair[0]);
fdpair[0] = fdset_remove(fds, fdpair[0]);
"exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", netns_fdpair[0]);
netns_fdpair[0] = fdset_remove(fds, netns_fdpair[0]);
if (v[n] != ' ')
goto finalize;
p = v + n + 1;
@@ -6419,17 +6503,56 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
n = strcspn(v, " ");
buf = strndupa(v, n);
r = safe_atoi(buf, &fdpair[1]);
r = safe_atoi(buf, &netns_fdpair[1]);
if (r < 0)
return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-1=%s: %m", buf);
if (!fdset_contains(fds, fdpair[1]))
if (!fdset_contains(fds, netns_fdpair[1]))
return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
"exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", fdpair[1]);
fdpair[1] = fdset_remove(fds, fdpair[1]);
"exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", netns_fdpair[1]);
netns_fdpair[1] = fdset_remove(fds, netns_fdpair[1]);
if (v[n] != ' ')
goto finalize;
p = v + n + 1;
}
v = startswith(p, "ipcns-socket-0=");
if (v) {
char *buf;
n = strcspn(v, " ");
buf = strndupa(v, n);
r = safe_atoi(buf, &ipcns_fdpair[0]);
if (r < 0)
return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-0=%s: %m", buf);
if (!fdset_contains(fds, ipcns_fdpair[0]))
return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
"exec-runtime specification ipcns-socket-0= refers to unknown fd %d: %m", ipcns_fdpair[0]);
ipcns_fdpair[0] = fdset_remove(fds, ipcns_fdpair[0]);
if (v[n] != ' ')
goto finalize;
p = v + n + 1;
}
v = startswith(p, "ipcns-socket-1=");
if (v) {
char *buf;
n = strcspn(v, " ");
buf = strndupa(v, n);
r = safe_atoi(buf, &ipcns_fdpair[1]);
if (r < 0)
return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-1=%s: %m", buf);
if (!fdset_contains(fds, ipcns_fdpair[1]))
return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
"exec-runtime specification ipcns-socket-1= refers to unknown fd %d: %m", ipcns_fdpair[1]);
ipcns_fdpair[1] = fdset_remove(fds, ipcns_fdpair[1]);
}
finalize:
r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, fdpair, NULL);
r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to add exec-runtime: %m");
return 0;
+5
View File
@@ -117,6 +117,9 @@ struct ExecRuntime {
/* An AF_UNIX socket pair, that contains a datagram containing a file descriptor referring to the network
* namespace. */
int netns_storage_socket[2];
/* Like netns_storage_socket, but the file descriptor is referring to the IPC namespace. */
int ipcns_storage_socket[2];
};
typedef enum ExecDirectoryType {
@@ -280,6 +283,7 @@ struct ExecContext {
bool private_devices;
bool private_users;
bool private_mounts;
bool private_ipc;
bool protect_kernel_tunables;
bool protect_kernel_modules;
bool protect_kernel_logs;
@@ -314,6 +318,7 @@ struct ExecContext {
Set *address_families;
char *network_namespace_path;
char *ipc_namespace_path;
ExecDirectory directories[_EXEC_DIRECTORY_TYPE_MAX];
ExecPreserveMode runtime_directory_preserve_mode;
+2
View File
@@ -133,10 +133,12 @@ $1.ProtectKernelLogs, config_parse_bool,
$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.IPCNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.ipc_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)
$1.PrivateIPC, config_parse_bool, 0, offsetof($1, exec_context.private_ipc)
$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.mount_flags)
+8
View File
@@ -1552,6 +1552,14 @@ static int socket_address_listen_in_cgroup(
return log_unit_error_errno(UNIT(s), r, "Failed to open network namespace path %s: %m", s->exec_context.network_namespace_path);
}
if (s->exec_context.ipc_namespace_path &&
s->exec_runtime &&
s->exec_runtime->ipcns_storage_socket[0] >= 0) {
r = open_shareable_ns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWIPC);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to open IPC namespace path %s: %m", s->exec_context.ipc_namespace_path);
}
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
+2
View File
@@ -882,6 +882,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"ProtectProc",
"ProcSubset",
"NetworkNamespacePath",
"IPCNamespacePath",
"LogNamespace"))
return bus_append_string(m, field, eq);
@@ -894,6 +895,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"PrivateNetwork",
"PrivateUsers",
"PrivateMounts",
"PrivateIPC",
"NoNewPrivileges",
"SyslogLevelPrefix",
"MemoryDenyWriteExecute",
+1 -1
View File
@@ -2,8 +2,8 @@
#include <fcntl.h>
#include <linux/magic.h>
#include <unistd.h>
#include <sched.h>
#include <unistd.h>
#include "alloc-util.h"
#include "fd-util.h"