mirror of
https://github.com/systemd/systemd
synced 2025-11-17 07:44:46 +01:00
Compare commits
7 Commits
0885e4a6e7
...
dd15dd1a58
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd15dd1a58 | ||
|
|
23fbaa463a | ||
|
|
f8574e252a | ||
|
|
f2875c73a2 | ||
|
|
9011b1cfc0 | ||
|
|
9e26ced980 | ||
|
|
456ee3c5f9 |
@ -101,7 +101,7 @@
|
|||||||
icon name to <replaceable>NAME</replaceable>. The icon name is used by some
|
icon name to <replaceable>NAME</replaceable>. The icon name is used by some
|
||||||
graphical applications to visualize this host. The icon name
|
graphical applications to visualize this host. The icon name
|
||||||
should follow the <ulink
|
should follow the <ulink
|
||||||
url="https://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html">Icon
|
url="https://specifications.freedesktop.org/icon-naming/latest">Icon
|
||||||
Naming Specification</ulink>.</para>
|
Naming Specification</ulink>.</para>
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v249"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v249"/></listitem>
|
||||||
|
|||||||
@ -291,6 +291,32 @@
|
|||||||
<xi:include href="version-info.xml" xpointer="v240"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v240"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--root-directory=</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Runs the service process with the specified root directory. Also see
|
||||||
|
<varname>RootDirectory=</varname> in
|
||||||
|
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||||
|
|
||||||
|
<para>Note that the path is looked up inside the file system namespace that systemd-run is running
|
||||||
|
in, which might be different that the file system namespace the manager process is running in. Use
|
||||||
|
the <varname>RootDirectory=</varname> property directly if you want the path to be looked up in the
|
||||||
|
manager process's file system namespace.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v259"/>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--same-root-dir</option></term>
|
||||||
|
<term><option>-R</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Similar to <option>--root-directory=</option>, but uses the root directory of the
|
||||||
|
systemd-run process as the root directory to execute the service in.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-E <replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
<term><option>-E <replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
||||||
<term><option>--setenv=<replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
<term><option>--setenv=<replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
||||||
|
|||||||
@ -254,6 +254,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||||||
" Run command on the namespace of the service\n"
|
" Run command on the namespace of the service\n"
|
||||||
"\n%3$sExecutable Analysis:%4$s\n"
|
"\n%3$sExecutable Analysis:%4$s\n"
|
||||||
" inspect-elf FILE... Parse and print ELF package metadata\n"
|
" inspect-elf FILE... Parse and print ELF package metadata\n"
|
||||||
|
" dlopen-metadata FILE Parse and print ELF dlopen metadata\n"
|
||||||
"\n%3$sTPM Operations:%4$s\n"
|
"\n%3$sTPM Operations:%4$s\n"
|
||||||
" has-tpm2 Report whether TPM2 support is available\n"
|
" has-tpm2 Report whether TPM2 support is available\n"
|
||||||
" pcrs [PCR...] Show TPM2 PCRs and their names\n"
|
" pcrs [PCR...] Show TPM2 PCRs and their names\n"
|
||||||
|
|||||||
@ -484,9 +484,8 @@ static int bus_set_transient_exit_status(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bus_set_transient_std_fd(
|
static int bus_set_transient_exec_context_fd(
|
||||||
Unit *u,
|
Unit *u,
|
||||||
const char *name,
|
|
||||||
int *p,
|
int *p,
|
||||||
bool *b,
|
bool *b,
|
||||||
sd_bus_message *message,
|
sd_bus_message *message,
|
||||||
@ -688,13 +687,13 @@ static int bus_service_set_transient_property(
|
|||||||
return bus_set_transient_exec_command(u, name, &s->exec_command[ci], message, flags, error);
|
return bus_set_transient_exec_command(u, name, &s->exec_command[ci], message, flags, error);
|
||||||
|
|
||||||
if (streq(name, "StandardInputFileDescriptor"))
|
if (streq(name, "StandardInputFileDescriptor"))
|
||||||
return bus_set_transient_std_fd(u, name, &s->stdin_fd, &s->exec_context.stdio_as_fds, message, flags, error);
|
return bus_set_transient_exec_context_fd(u, &s->stdin_fd, &s->exec_context.stdio_as_fds, message, flags, error);
|
||||||
|
|
||||||
if (streq(name, "StandardOutputFileDescriptor"))
|
if (streq(name, "StandardOutputFileDescriptor"))
|
||||||
return bus_set_transient_std_fd(u, name, &s->stdout_fd, &s->exec_context.stdio_as_fds, message, flags, error);
|
return bus_set_transient_exec_context_fd(u, &s->stdout_fd, &s->exec_context.stdio_as_fds, message, flags, error);
|
||||||
|
|
||||||
if (streq(name, "StandardErrorFileDescriptor"))
|
if (streq(name, "StandardErrorFileDescriptor"))
|
||||||
return bus_set_transient_std_fd(u, name, &s->stderr_fd, &s->exec_context.stdio_as_fds, message, flags, error);
|
return bus_set_transient_exec_context_fd(u, &s->stderr_fd, &s->exec_context.stdio_as_fds, message, flags, error);
|
||||||
|
|
||||||
if (streq(name, "OpenFile")) {
|
if (streq(name, "OpenFile")) {
|
||||||
const char *path, *fdname;
|
const char *path, *fdname;
|
||||||
@ -800,6 +799,9 @@ static int bus_service_set_transient_property(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (streq(name, "RootDirectoryFileDescriptor"))
|
||||||
|
return bus_set_transient_exec_context_fd(u, &s->root_directory_fd, &s->exec_context.root_directory_as_fd, message, flags, error);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3470,7 +3470,7 @@ static bool insist_on_sandboxing(
|
|||||||
if (context->n_temporary_filesystems > 0)
|
if (context->n_temporary_filesystems > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (root_dir || root_image)
|
if (root_dir || root_image || context->root_directory_as_fd)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (context->n_mount_images > 0)
|
if (context->n_mount_images > 0)
|
||||||
@ -3506,6 +3506,7 @@ static int setup_ephemeral(
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(context);
|
assert(context);
|
||||||
|
assert(!context->root_directory_as_fd);
|
||||||
assert(runtime);
|
assert(runtime);
|
||||||
assert(root_image);
|
assert(root_image);
|
||||||
assert(root_directory);
|
assert(root_directory);
|
||||||
@ -3645,6 +3646,7 @@ static int pick_versions(
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(context);
|
assert(context);
|
||||||
|
assert(!context->root_directory_as_fd);
|
||||||
assert(params);
|
assert(params);
|
||||||
assert(ret_root_image);
|
assert(ret_root_image);
|
||||||
assert(ret_root_directory);
|
assert(ret_root_directory);
|
||||||
@ -3733,7 +3735,7 @@ static int apply_mount_namespace(
|
|||||||
|
|
||||||
CLEANUP_ARRAY(bind_mounts, n_bind_mounts, bind_mount_free_many);
|
CLEANUP_ARRAY(bind_mounts, n_bind_mounts, bind_mount_free_many);
|
||||||
|
|
||||||
if (params->flags & EXEC_APPLY_CHROOT) {
|
if (params->flags & EXEC_APPLY_CHROOT && !context->root_directory_as_fd) {
|
||||||
r = pick_versions(
|
r = pick_versions(
|
||||||
context,
|
context,
|
||||||
params,
|
params,
|
||||||
@ -3855,6 +3857,7 @@ static int apply_mount_namespace(
|
|||||||
|
|
||||||
.root_directory = root_dir,
|
.root_directory = root_dir,
|
||||||
.root_image = root_image,
|
.root_image = root_image,
|
||||||
|
.root_directory_fd = params->flags & EXEC_APPLY_CHROOT ? params->root_directory_fd : -EBADF,
|
||||||
.root_image_options = context->root_image_options,
|
.root_image_options = context->root_image_options,
|
||||||
.root_image_policy = context->root_image_policy ?: &image_policy_service,
|
.root_image_policy = context->root_image_policy ?: &image_policy_service,
|
||||||
|
|
||||||
@ -4444,13 +4447,13 @@ static int collect_open_file_fds(ExecParameters *p) {
|
|||||||
return log_error_errno(fd, "Failed to get OpenFile= file descriptor for '%s': %m", of->path);
|
return log_error_errno(fd, "Failed to get OpenFile= file descriptor for '%s': %m", of->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GREEDY_REALLOC(p->fds, p->n_stashed_fds + 1))
|
if (!GREEDY_REALLOC(p->fds, p->n_socket_fds + p->n_stashed_fds + 1))
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (strv_extend(&p->fd_names, of->fdname) < 0)
|
if (strv_extend(&p->fd_names, of->fdname) < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
p->fds[p->n_stashed_fds++] = TAKE_FD(fd);
|
p->fds[p->n_socket_fds + p->n_stashed_fds++] = TAKE_FD(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -4495,6 +4498,7 @@ static bool exec_needs_cap_sys_admin(const ExecContext *context, const ExecParam
|
|||||||
context->n_bind_mounts > 0 ||
|
context->n_bind_mounts > 0 ||
|
||||||
context->n_temporary_filesystems > 0 ||
|
context->n_temporary_filesystems > 0 ||
|
||||||
context->root_directory ||
|
context->root_directory ||
|
||||||
|
context->root_directory_as_fd ||
|
||||||
!strv_isempty(context->extension_directories) ||
|
!strv_isempty(context->extension_directories) ||
|
||||||
context->root_image ||
|
context->root_image ||
|
||||||
context->n_mount_images > 0 ||
|
context->n_mount_images > 0 ||
|
||||||
@ -5136,6 +5140,12 @@ int exec_invoke(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
r = add_shifted_fd(&keep_fds, &n_keep_fds, ¶ms->root_directory_fd);
|
||||||
|
if (r < 0) {
|
||||||
|
*exit_status = EXIT_FDS;
|
||||||
|
return log_error_errno(r, "Failed to collect shifted fd: %m");
|
||||||
|
}
|
||||||
|
|
||||||
r = close_remaining_fds(params, runtime, socket_fd, keep_fds, n_keep_fds);
|
r = close_remaining_fds(params, runtime, socket_fd, keep_fds, n_keep_fds);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
*exit_status = EXIT_FDS;
|
*exit_status = EXIT_FDS;
|
||||||
|
|||||||
@ -1177,6 +1177,10 @@ static int exec_parameters_serialize(const ExecParameters *p, const ExecContext
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
r = serialize_fd(f, fds, "exec-parameters-root-directory-fd", p->root_directory_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = serialize_fd(f, fds, "exec-parameters-exec-fd", p->exec_fd);
|
r = serialize_fd(f, fds, "exec-parameters-exec-fd", p->exec_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1422,6 +1426,16 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
close_and_replace(p->stderr_fd, fd);
|
close_and_replace(p->stderr_fd, fd);
|
||||||
|
|
||||||
|
} else if ((val = startswith(l, "exec-parameters-root-directory-fd="))) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = deserialize_fd(fds, val);
|
||||||
|
if (fd < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
close_and_replace(p->root_directory_fd, fd);
|
||||||
|
|
||||||
} else if ((val = startswith(l, "exec-parameters-exec-fd="))) {
|
} else if ((val = startswith(l, "exec-parameters-exec-fd="))) {
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@ -1994,6 +2008,10 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
r = serialize_bool_elide(f, "exec-context-root-directory-as-fd", c->root_directory_as_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
switch (c->std_input) {
|
switch (c->std_input) {
|
||||||
case EXEC_INPUT_NAMED_FD:
|
case EXEC_INPUT_NAMED_FD:
|
||||||
r = serialize_item(f, "exec-context-std-input-fd-name", c->stdio_fdname[STDIN_FILENO]);
|
r = serialize_item(f, "exec-context-std-input-fd-name", c->stdio_fdname[STDIN_FILENO]);
|
||||||
@ -3000,6 +3018,11 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
c->stdio_as_fds = r;
|
c->stdio_as_fds = r;
|
||||||
|
} else if ((val = startswith(l, "exec-context-root-directory-as-fd="))) {
|
||||||
|
r = parse_boolean(val);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
c->root_directory_as_fd = r;
|
||||||
} else if ((val = startswith(l, "exec-context-std-input-fd-name="))) {
|
} else if ((val = startswith(l, "exec-context-std-input-fd-name="))) {
|
||||||
r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], val);
|
r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], val);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -267,6 +267,9 @@ bool exec_needs_mount_namespace(
|
|||||||
if (context->root_image)
|
if (context->root_image)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (context->root_directory_as_fd)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (!strv_isempty(context->read_write_paths) ||
|
if (!strv_isempty(context->read_write_paths) ||
|
||||||
!strv_isempty(context->read_only_paths) ||
|
!strv_isempty(context->read_only_paths) ||
|
||||||
!strv_isempty(context->inaccessible_paths) ||
|
!strv_isempty(context->inaccessible_paths) ||
|
||||||
@ -354,7 +357,7 @@ const char* exec_get_private_notify_socket_path(const ExecContext *context, cons
|
|||||||
if (!needs_sandboxing)
|
if (!needs_sandboxing)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!context->root_directory && !context->root_image)
|
if (!context->root_directory && !context->root_image && !context->root_directory_as_fd)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!exec_context_get_effective_mount_apivfs(context))
|
if (!exec_context_get_effective_mount_apivfs(context))
|
||||||
@ -2045,9 +2048,9 @@ bool exec_context_restrict_filesystems_set(const ExecContext *c) {
|
|||||||
bool exec_context_with_rootfs(const ExecContext *c) {
|
bool exec_context_with_rootfs(const ExecContext *c) {
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
/* Checks if RootDirectory= or RootImage= are used */
|
/* Checks if RootDirectory=, RootImage= or RootDirectoryFileDescriptor= are used */
|
||||||
|
|
||||||
return !empty_or_root(c->root_directory) || c->root_image;
|
return !empty_or_root(c->root_directory) || c->root_image || c->root_directory_as_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int exec_context_has_vpicked_extensions(const ExecContext *context) {
|
int exec_context_has_vpicked_extensions(const ExecContext *context) {
|
||||||
@ -2846,6 +2849,7 @@ void exec_params_deep_clear(ExecParameters *p) {
|
|||||||
p->stdin_fd = safe_close(p->stdin_fd);
|
p->stdin_fd = safe_close(p->stdin_fd);
|
||||||
p->stdout_fd = safe_close(p->stdout_fd);
|
p->stdout_fd = safe_close(p->stdout_fd);
|
||||||
p->stderr_fd = safe_close(p->stderr_fd);
|
p->stderr_fd = safe_close(p->stderr_fd);
|
||||||
|
p->root_directory_fd = safe_close(p->root_directory_fd);
|
||||||
|
|
||||||
p->notify_socket = mfree(p->notify_socket);
|
p->notify_socket = mfree(p->notify_socket);
|
||||||
|
|
||||||
|
|||||||
@ -218,6 +218,7 @@ typedef struct ExecContext {
|
|||||||
/* At least one of stdin/stdout/stderr was initialized from an fd passed in. This boolean survives
|
/* At least one of stdin/stdout/stderr was initialized from an fd passed in. This boolean survives
|
||||||
* the fds being closed. This only makes sense for transient units. */
|
* the fds being closed. This only makes sense for transient units. */
|
||||||
bool stdio_as_fds;
|
bool stdio_as_fds;
|
||||||
|
bool root_directory_as_fd;
|
||||||
|
|
||||||
char *stdio_fdname[3];
|
char *stdio_fdname[3];
|
||||||
char *stdio_file[3];
|
char *stdio_file[3];
|
||||||
@ -418,6 +419,7 @@ typedef struct ExecParameters {
|
|||||||
int stdin_fd;
|
int stdin_fd;
|
||||||
int stdout_fd;
|
int stdout_fd;
|
||||||
int stderr_fd;
|
int stderr_fd;
|
||||||
|
int root_directory_fd;
|
||||||
|
|
||||||
/* An fd that is closed by the execve(), and thus will result in EOF when the execve() is done. */
|
/* An fd that is closed by the execve(), and thus will result in EOF when the execve() is done. */
|
||||||
int exec_fd;
|
int exec_fd;
|
||||||
@ -449,6 +451,7 @@ typedef struct ExecParameters {
|
|||||||
.stdin_fd = -EBADF, \
|
.stdin_fd = -EBADF, \
|
||||||
.stdout_fd = -EBADF, \
|
.stdout_fd = -EBADF, \
|
||||||
.stderr_fd = -EBADF, \
|
.stderr_fd = -EBADF, \
|
||||||
|
.root_directory_fd = -EBADF, \
|
||||||
.exec_fd = -EBADF, \
|
.exec_fd = -EBADF, \
|
||||||
.bpf_restrict_fs_map_fd = -EBADF, \
|
.bpf_restrict_fs_map_fd = -EBADF, \
|
||||||
.user_lookup_fd = -EBADF, \
|
.user_lookup_fd = -EBADF, \
|
||||||
|
|||||||
@ -58,6 +58,7 @@ static void exec_fuzz_one(FILE *f, FDSet *fdset) {
|
|||||||
params.stdin_fd = -EBADF;
|
params.stdin_fd = -EBADF;
|
||||||
params.stdout_fd = -EBADF;
|
params.stdout_fd = -EBADF;
|
||||||
params.stderr_fd = -EBADF;
|
params.stderr_fd = -EBADF;
|
||||||
|
params.root_directory_fd = -EBADF;
|
||||||
params.exec_fd = -EBADF;
|
params.exec_fd = -EBADF;
|
||||||
params.user_lookup_fd = -EBADF;
|
params.user_lookup_fd = -EBADF;
|
||||||
params.bpf_restrict_fs_map_fd = -EBADF;
|
params.bpf_restrict_fs_map_fd = -EBADF;
|
||||||
|
|||||||
@ -1359,7 +1359,7 @@ static int mount_private_dev(const MountEntry *m, const NamespaceParameters *p)
|
|||||||
|
|
||||||
/* We assume /run/systemd/journal/ is available if not changing root, which isn't entirely accurate
|
/* We assume /run/systemd/journal/ is available if not changing root, which isn't entirely accurate
|
||||||
* but shouldn't matter, as either way the user would get ENOENT when accessing /dev/log */
|
* but shouldn't matter, as either way the user would get ENOENT when accessing /dev/log */
|
||||||
if ((!p->root_image && !p->root_directory) || p->bind_log_sockets) {
|
if ((!p->root_image && !p->root_directory && p->root_directory_fd < 0) || p->bind_log_sockets) {
|
||||||
const char *devlog = strjoina(temporary_mount, "/dev/log");
|
const char *devlog = strjoina(temporary_mount, "/dev/log");
|
||||||
if (symlink("/run/systemd/journal/dev-log", devlog) < 0)
|
if (symlink("/run/systemd/journal/dev-log", devlog) < 0)
|
||||||
log_debug_errno(errno,
|
log_debug_errno(errno,
|
||||||
@ -2948,7 +2948,18 @@ int setup_namespace(const NamespaceParameters *p, char **reterr_path) {
|
|||||||
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
|
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
|
||||||
return log_debug_errno(errno, "Failed to remount '/' as SLAVE: %m");
|
return log_debug_errno(errno, "Failed to remount '/' as SLAVE: %m");
|
||||||
|
|
||||||
if (p->root_image) {
|
if (p->root_directory_fd >= 0) {
|
||||||
|
|
||||||
|
if (move_mount(p->root_directory_fd, "", AT_FDCWD, root, MOVE_MOUNT_F_EMPTY_PATH) < 0)
|
||||||
|
return log_debug_errno(errno, "Failed to move detached mount to '%s': %m", root);
|
||||||
|
|
||||||
|
/* We just remounted / as slave, but that didn't affect the detached mount that we just
|
||||||
|
* mounted, so remount that one as slave recursive as well now. */
|
||||||
|
|
||||||
|
if (mount(NULL, root, NULL, MS_SLAVE|MS_REC, NULL) < 0)
|
||||||
|
return log_debug_errno(errno, "Failed to remount '%s' as SLAVE: %m", root);
|
||||||
|
|
||||||
|
} else if (p->root_image) {
|
||||||
/* A root image is specified, mount it to the right place */
|
/* A root image is specified, mount it to the right place */
|
||||||
r = dissected_image_mount(
|
r = dissected_image_mount(
|
||||||
dissected_image,
|
dissected_image,
|
||||||
@ -2992,7 +3003,7 @@ int setup_namespace(const NamespaceParameters *p, char **reterr_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Try to set up the new root directory before mounting anything else there. */
|
/* Try to set up the new root directory before mounting anything else there. */
|
||||||
if (p->root_image || p->root_directory)
|
if (p->root_image || p->root_directory || p->root_directory_fd >= 0)
|
||||||
(void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
|
(void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
|
||||||
|
|
||||||
/* Now make the magic happen */
|
/* Now make the magic happen */
|
||||||
|
|||||||
@ -128,6 +128,7 @@ typedef struct MountImage {
|
|||||||
typedef struct NamespaceParameters {
|
typedef struct NamespaceParameters {
|
||||||
RuntimeScope runtime_scope;
|
RuntimeScope runtime_scope;
|
||||||
|
|
||||||
|
int root_directory_fd;
|
||||||
const char *root_directory;
|
const char *root_directory;
|
||||||
const char *root_image;
|
const char *root_image;
|
||||||
const MountOptions *root_image_options;
|
const MountOptions *root_image_options;
|
||||||
|
|||||||
@ -165,6 +165,7 @@ static void service_init(Unit *u) {
|
|||||||
s->type = _SERVICE_TYPE_INVALID;
|
s->type = _SERVICE_TYPE_INVALID;
|
||||||
s->socket_fd = -EBADF;
|
s->socket_fd = -EBADF;
|
||||||
s->stdin_fd = s->stdout_fd = s->stderr_fd = -EBADF;
|
s->stdin_fd = s->stdout_fd = s->stderr_fd = -EBADF;
|
||||||
|
s->root_directory_fd = -EBADF;
|
||||||
s->guess_main_pid = true;
|
s->guess_main_pid = true;
|
||||||
s->main_pid = PIDREF_NULL;
|
s->main_pid = PIDREF_NULL;
|
||||||
s->control_pid = PIDREF_NULL;
|
s->control_pid = PIDREF_NULL;
|
||||||
@ -542,6 +543,7 @@ static void service_done(Unit *u) {
|
|||||||
service_release_stdio_fd(s);
|
service_release_stdio_fd(s);
|
||||||
service_release_fd_store(s);
|
service_release_fd_store(s);
|
||||||
service_release_extra_fds(s);
|
service_release_extra_fds(s);
|
||||||
|
s->root_directory_fd = asynchronous_close(s->root_directory_fd);
|
||||||
|
|
||||||
s->mount_request = sd_bus_message_unref(s->mount_request);
|
s->mount_request = sd_bus_message_unref(s->mount_request);
|
||||||
}
|
}
|
||||||
@ -1108,6 +1110,9 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
|
|||||||
f,
|
f,
|
||||||
prefix);
|
prefix);
|
||||||
|
|
||||||
|
if (s->root_directory_fd >= 0)
|
||||||
|
(void) service_dump_fd(s->root_directory_fd, "Root Directory File Descriptor", "", f, prefix);
|
||||||
|
|
||||||
if (s->open_files)
|
if (s->open_files)
|
||||||
LIST_FOREACH(open_files, of, s->open_files) {
|
LIST_FOREACH(open_files, of, s->open_files) {
|
||||||
_cleanup_free_ char *ofs = NULL;
|
_cleanup_free_ char *ofs = NULL;
|
||||||
@ -1925,6 +1930,7 @@ static int service_spawn_internal(
|
|||||||
exec_params.stdin_fd = s->stdin_fd;
|
exec_params.stdin_fd = s->stdin_fd;
|
||||||
exec_params.stdout_fd = s->stdout_fd;
|
exec_params.stdout_fd = s->stdout_fd;
|
||||||
exec_params.stderr_fd = s->stderr_fd;
|
exec_params.stderr_fd = s->stderr_fd;
|
||||||
|
exec_params.root_directory_fd = s->root_directory_fd;
|
||||||
|
|
||||||
r = exec_spawn(UNIT(s),
|
r = exec_spawn(UNIT(s),
|
||||||
c,
|
c,
|
||||||
@ -2834,6 +2840,7 @@ static void service_enter_refresh_extensions(Service *s) {
|
|||||||
.n_extension_images = s->exec_context.n_extension_images,
|
.n_extension_images = s->exec_context.n_extension_images,
|
||||||
.extension_directories = s->exec_context.extension_directories,
|
.extension_directories = s->exec_context.extension_directories,
|
||||||
.extension_image_policy = s->exec_context.extension_image_policy,
|
.extension_image_policy = s->exec_context.extension_image_policy,
|
||||||
|
.root_directory_fd = -EBADF,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Only reload confext, and not sysext as they also typically contain the executable(s) used
|
/* Only reload confext, and not sysext as they also typically contain the executable(s) used
|
||||||
@ -3226,13 +3233,19 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
|
|||||||
r = serialize_fd(f, fds, "stdin-fd", s->stdin_fd);
|
r = serialize_fd(f, fds, "stdin-fd", s->stdin_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = serialize_fd(f, fds, "stdout-fd", s->stdout_fd);
|
r = serialize_fd(f, fds, "stdout-fd", s->stdout_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = serialize_fd(f, fds, "stderr-fd", s->stderr_fd);
|
r = serialize_fd(f, fds, "stderr-fd", s->stderr_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
r = serialize_fd(f, fds, "root-directory-fd", s->root_directory_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
if (s->exec_fd_event_source) {
|
if (s->exec_fd_event_source) {
|
||||||
r = serialize_fd(f, fds, "exec-fd", sd_event_source_get_io_fd(s->exec_fd_event_source));
|
r = serialize_fd(f, fds, "exec-fd", sd_event_source_get_io_fd(s->exec_fd_event_source));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -3637,6 +3650,13 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
|
|||||||
if (s->stderr_fd >= 0)
|
if (s->stderr_fd >= 0)
|
||||||
s->exec_context.stdio_as_fds = true;
|
s->exec_context.stdio_as_fds = true;
|
||||||
|
|
||||||
|
} else if (streq(key, "root-directory-fd")) {
|
||||||
|
|
||||||
|
asynchronous_close(s->root_directory_fd);
|
||||||
|
s->root_directory_fd = deserialize_fd(fds, value);
|
||||||
|
if (s->root_directory_fd >= 0)
|
||||||
|
s->exec_context.root_directory_as_fd = true;
|
||||||
|
|
||||||
} else if (streq(key, "exec-fd")) {
|
} else if (streq(key, "exec-fd")) {
|
||||||
_cleanup_close_ int fd = -EBADF;
|
_cleanup_close_ int fd = -EBADF;
|
||||||
|
|
||||||
@ -5589,6 +5609,7 @@ static void service_release_resources(Unit *u) {
|
|||||||
service_release_socket_fd(s);
|
service_release_socket_fd(s);
|
||||||
service_release_stdio_fd(s);
|
service_release_stdio_fd(s);
|
||||||
service_release_extra_fds(s);
|
service_release_extra_fds(s);
|
||||||
|
s->root_directory_fd = asynchronous_close(s->root_directory_fd);
|
||||||
|
|
||||||
if (s->fd_store_preserve_mode != EXEC_PRESERVE_YES)
|
if (s->fd_store_preserve_mode != EXEC_PRESERVE_YES)
|
||||||
service_release_fd_store(s);
|
service_release_fd_store(s);
|
||||||
@ -5622,7 +5643,10 @@ int service_determine_exec_selinux_label(Service *s, char **ret) {
|
|||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
|
|
||||||
_cleanup_free_ char *path = NULL;
|
_cleanup_free_ char *path = NULL;
|
||||||
r = chase(c->path, s->exec_context.root_directory, CHASE_PREFIX_ROOT|CHASE_TRIGGER_AUTOFS, &path, NULL);
|
if (s->exec_context.root_directory_as_fd)
|
||||||
|
r = chaseat(s->root_directory_fd, c->path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_TRIGGER_AUTOFS, &path, NULL);
|
||||||
|
else
|
||||||
|
r = chase(c->path, s->exec_context.root_directory, CHASE_PREFIX_ROOT|CHASE_TRIGGER_AUTOFS, &path, NULL);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_unit_debug_errno(UNIT(s), r, "Failed to resolve service binary '%s', ignoring.", c->path);
|
log_unit_debug_errno(UNIT(s), r, "Failed to resolve service binary '%s', ignoring.", c->path);
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
|
|||||||
@ -224,6 +224,9 @@ typedef struct Service {
|
|||||||
int stdout_fd;
|
int stdout_fd;
|
||||||
int stderr_fd;
|
int stderr_fd;
|
||||||
|
|
||||||
|
/* File descriptor received from RootDirectoryFileDescriptor= */
|
||||||
|
int root_directory_fd;
|
||||||
|
|
||||||
/* If service spawned from transient unit, extra file descriptors can be passed via dbus API */
|
/* If service spawned from transient unit, extra file descriptors can be passed via dbus API */
|
||||||
ServiceExtraFD *extra_fds;
|
ServiceExtraFD *extra_fds;
|
||||||
size_t n_extra_fds;
|
size_t n_extra_fds;
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -106,6 +107,7 @@ static bool arg_quiet = false;
|
|||||||
static bool arg_verbose = false;
|
static bool arg_verbose = false;
|
||||||
static bool arg_aggressive_gc = false;
|
static bool arg_aggressive_gc = false;
|
||||||
static char *arg_working_directory = NULL;
|
static char *arg_working_directory = NULL;
|
||||||
|
static char *arg_root_directory = NULL;
|
||||||
static bool arg_shell = false;
|
static bool arg_shell = false;
|
||||||
static JobMode arg_job_mode = JOB_FAIL;
|
static JobMode arg_job_mode = JOB_FAIL;
|
||||||
static char **arg_cmdline = NULL;
|
static char **arg_cmdline = NULL;
|
||||||
@ -168,6 +170,8 @@ static int help(void) {
|
|||||||
" --nice=NICE Nice level\n"
|
" --nice=NICE Nice level\n"
|
||||||
" --working-directory=PATH Set working directory\n"
|
" --working-directory=PATH Set working directory\n"
|
||||||
" -d --same-dir Inherit working directory from caller\n"
|
" -d --same-dir Inherit working directory from caller\n"
|
||||||
|
" --root-directory=PATH Set root directory\n"
|
||||||
|
" -R --same-root-dir Inherit root directory from caller\n"
|
||||||
" -E --setenv=NAME[=VALUE] Set environment variable\n"
|
" -E --setenv=NAME[=VALUE] Set environment variable\n"
|
||||||
" -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n"
|
" -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n"
|
||||||
" STDERR\n"
|
" STDERR\n"
|
||||||
@ -326,6 +330,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
ARG_NO_ASK_PASSWORD,
|
ARG_NO_ASK_PASSWORD,
|
||||||
ARG_WAIT,
|
ARG_WAIT,
|
||||||
ARG_WORKING_DIRECTORY,
|
ARG_WORKING_DIRECTORY,
|
||||||
|
ARG_ROOT_DIRECTORY,
|
||||||
ARG_SHELL,
|
ARG_SHELL,
|
||||||
ARG_JOB_MODE,
|
ARG_JOB_MODE,
|
||||||
ARG_IGNORE_FAILURE,
|
ARG_IGNORE_FAILURE,
|
||||||
@ -379,6 +384,8 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "collect", no_argument, NULL, 'G' },
|
{ "collect", no_argument, NULL, 'G' },
|
||||||
{ "working-directory", required_argument, NULL, ARG_WORKING_DIRECTORY },
|
{ "working-directory", required_argument, NULL, ARG_WORKING_DIRECTORY },
|
||||||
{ "same-dir", no_argument, NULL, 'd' },
|
{ "same-dir", no_argument, NULL, 'd' },
|
||||||
|
{ "root-directory", required_argument, NULL, ARG_ROOT_DIRECTORY },
|
||||||
|
{ "same-root-dir", no_argument, NULL, 'R' },
|
||||||
{ "shell", no_argument, NULL, 'S' },
|
{ "shell", no_argument, NULL, 'S' },
|
||||||
{ "job-mode", required_argument, NULL, ARG_JOB_MODE },
|
{ "job-mode", required_argument, NULL, ARG_JOB_MODE },
|
||||||
{ "ignore-failure", no_argument, NULL, ARG_IGNORE_FAILURE },
|
{ "ignore-failure", no_argument, NULL, ARG_IGNORE_FAILURE },
|
||||||
@ -388,7 +395,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
bool with_trigger = false;
|
bool with_trigger = false, same_dir = false;
|
||||||
int r, c;
|
int r, c;
|
||||||
|
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
@ -653,6 +660,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
same_dir = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd': {
|
case 'd': {
|
||||||
@ -666,9 +674,25 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
arg_working_directory = mfree(arg_working_directory);
|
arg_working_directory = mfree(arg_working_directory);
|
||||||
else
|
else
|
||||||
free_and_replace(arg_working_directory, p);
|
free_and_replace(arg_working_directory, p);
|
||||||
|
|
||||||
|
same_dir = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ARG_ROOT_DIRECTORY:
|
||||||
|
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_root_directory);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'R':
|
||||||
|
r = free_and_strdup_warn(&arg_root_directory, "/");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case 'G':
|
case 'G':
|
||||||
arg_aggressive_gc = true;
|
arg_aggressive_gc = true;
|
||||||
break;
|
break;
|
||||||
@ -842,6 +866,10 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
"--wait may not be combined with --scope.");
|
"--wait may not be combined with --scope.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (same_dir && arg_root_directory && !path_equal(arg_root_directory, "/"))
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
|
"--same-dir cannot be used with a root directory other than '/'");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1406,6 +1434,16 @@ static int transient_service_set_properties(sd_bus_message *m, const char *pty_p
|
|||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg_root_directory) {
|
||||||
|
_cleanup_close_ int fd = open_tree(AT_FDCWD, arg_root_directory, OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC|AT_RECURSIVE);
|
||||||
|
if (fd < 0)
|
||||||
|
return log_error_errno(errno, "Failed to clone mount tree at '%s': %m", arg_root_directory);
|
||||||
|
|
||||||
|
r = sd_bus_message_append(m, "(sv)", "RootDirectoryFileDescriptor", "h", fd);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
}
|
||||||
|
|
||||||
if (pty_path) {
|
if (pty_path) {
|
||||||
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)",
|
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)",
|
||||||
"TTYPath", "s", pty_path,
|
"TTYPath", "s", pty_path,
|
||||||
|
|||||||
@ -259,7 +259,7 @@ static int reread_partition_table_full(sd_device *dev, int fd, RereadPartitionTa
|
|||||||
if (lock_fd < 0)
|
if (lock_fd < 0)
|
||||||
return log_device_debug_errno(dev, r, "Failed top open lock fd for block device '%s': %m", p);
|
return log_device_debug_errno(dev, r, "Failed top open lock fd for block device '%s': %m", p);
|
||||||
|
|
||||||
if (flock(lock_fd, LOCK_SH|LOCK_NB) < 0)
|
if (flock(lock_fd, LOCK_EX|LOCK_NB) < 0)
|
||||||
return log_device_debug_errno(dev, errno, "Failed to take BSD lock on block device '%s': %m", p);
|
return log_device_debug_errno(dev, errno, "Failed to take BSD lock on block device '%s': %m", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -201,6 +201,7 @@ TEST(protect_kernel_logs) {
|
|||||||
static const NamespaceParameters p = {
|
static const NamespaceParameters p = {
|
||||||
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
|
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
|
||||||
.protect_kernel_logs = true,
|
.protect_kernel_logs = true,
|
||||||
|
.root_directory_fd = -EBADF,
|
||||||
};
|
};
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
|||||||
@ -81,6 +81,7 @@ int main(int argc, char *argv[]) {
|
|||||||
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
|
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
|
||||||
|
|
||||||
.root_directory = root_directory,
|
.root_directory = root_directory,
|
||||||
|
.root_directory_fd = -EBADF,
|
||||||
|
|
||||||
.read_write_paths = (char**) writable,
|
.read_write_paths = (char**) writable,
|
||||||
.read_only_paths = (char**) readonly,
|
.read_only_paths = (char**) readonly,
|
||||||
|
|||||||
@ -890,6 +890,9 @@ systemctl stop test-root-ephemeral
|
|||||||
timeout 10 bash -c 'until test -z "$(ls -A /var/lib/systemd/ephemeral-trees)"; do sleep .5; done'
|
timeout 10 bash -c 'until test -z "$(ls -A /var/lib/systemd/ephemeral-trees)"; do sleep .5; done'
|
||||||
test ! -f /tmp/img/abc
|
test ! -f /tmp/img/abc
|
||||||
|
|
||||||
|
# Test RootDirectoryFileDescriptor=
|
||||||
|
systemd-run --wait --pipe --root-directory=/tmp/img -- grep -q 'MARKER=1' /usr/lib/os-release
|
||||||
|
|
||||||
systemd-dissect --mtree /tmp/img >/dev/null
|
systemd-dissect --mtree /tmp/img >/dev/null
|
||||||
systemd-dissect --list /tmp/img >/dev/null
|
systemd-dissect --list /tmp/img >/dev/null
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user