mirror of
https://github.com/systemd/systemd
synced 2025-11-17 15:54:45 +01:00
Compare commits
24 Commits
b5d63191ca
...
96d03f8e41
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96d03f8e41 | ||
|
|
056f437487 | ||
|
|
a274cb0cff | ||
|
|
f70346fb87 | ||
|
|
f4314f2fbc | ||
|
|
d93fff5c0c | ||
|
|
c954830fa9 | ||
|
|
d85d98f406 | ||
|
|
f78e7ca7da | ||
|
|
3299fb4ba7 | ||
|
|
75e05a9880 | ||
|
|
edb8fcd813 | ||
|
|
04072ad9ed | ||
|
|
234d8f8bc3 | ||
|
|
e984e2ca26 | ||
|
|
2fd2d8d575 | ||
|
|
a79d2e47fc | ||
|
|
5cabeed80b | ||
|
|
19bf12bff3 | ||
|
|
b1856a6c4a | ||
|
|
16f4bc90d2 | ||
|
|
a835537f75 | ||
|
|
3780a0b446 | ||
|
|
faaed501e0 |
@ -39,7 +39,7 @@ jobs:
|
||||
trigger: pull_request
|
||||
fmf_url: https://src.fedoraproject.org/rpms/systemd
|
||||
# This is automatically updated by tools/fetch-distro.py --update fedora
|
||||
fmf_ref: 7de88c66bdc26920db570e67ef74e579f8461d9c
|
||||
fmf_ref: ea1d871ecd6c2fe063523840c1e4cf9bcf200e32
|
||||
targets:
|
||||
- fedora-rawhide-x86_64
|
||||
# testing-farm in the Fedora repository is explicitly configured to use testing-farm bare metal runners as
|
||||
|
||||
15
man/run0.xml
15
man/run0.xml
@ -139,8 +139,8 @@
|
||||
<term><option>-g</option></term>
|
||||
|
||||
<listitem><para>Switches to the specified user/group. If not specified defaults to
|
||||
<literal>root</literal>, unless <option>--area=</option> is used (see below), in which case this
|
||||
defaults to the invoking user.</para>
|
||||
<literal>root</literal>, unless <option>--area=</option> or <option>--empower</option> are used (see
|
||||
below), in which case this defaults to the invoking user.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
@ -290,6 +290,17 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--empower</option></term>
|
||||
|
||||
<listitem><para>If specified, run0 will elevate the privileges of the selected user (using
|
||||
<option>--user=</option>) or the current user if no user is explicitly selected. Currently this means
|
||||
we give the user all available capabilities, but other privileges may be granted in the future as
|
||||
well when using this option.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--machine=</option></term>
|
||||
|
||||
|
||||
@ -463,7 +463,7 @@
|
||||
|
||||
<para>If used with <command>predict</command> and <command>make-policy</command> this will override
|
||||
which PCRs to include in the prediction and policy. If unspecified this defaults to PCRs 0-5, 7,
|
||||
11-15. Note that these commands will not include any PCRs in the prediction/policy (even if specified
|
||||
11, 13-15. Note that these commands will not include any PCRs in the prediction/policy (even if specified
|
||||
explicitly) if there are measurements in the event log that do not match the current PCR value, or
|
||||
there are unrecognized measurements in the event log, or components define measurements not seen in
|
||||
the event log.</para>
|
||||
|
||||
@ -4,5 +4,5 @@
|
||||
Environment=
|
||||
GIT_URL=https://src.fedoraproject.org/rpms/systemd.git
|
||||
GIT_BRANCH=rawhide
|
||||
GIT_COMMIT=7de88c66bdc26920db570e67ef74e579f8461d9c
|
||||
GIT_COMMIT=ea1d871ecd6c2fe063523840c1e4cf9bcf200e32
|
||||
PKG_SUBDIR=fedora
|
||||
|
||||
@ -82,6 +82,7 @@ CXX_LD="$( ((LLVM)) && echo lld)" \
|
||||
--noprep \
|
||||
--build-in-place \
|
||||
--with upstream \
|
||||
--without lto \
|
||||
$( ((WITH_TESTS)) || echo "--nocheck") \
|
||||
$( ((WITH_DOCS)) || echo "--without=docs") \
|
||||
--define "_topdir /var/tmp" \
|
||||
|
||||
@ -37,7 +37,7 @@ _run0() {
|
||||
--machine --unit --property --description --slice -u --user -g --group --nice -D --chdir
|
||||
--setenv --background
|
||||
)
|
||||
local OPTS="${opts_with_values[*]} -h --help -V --version --no-ask-password --slice-inherit"
|
||||
local OPTS="${opts_with_values[*]} -h --help -V --version --no-ask-password --slice-inherit --empower"
|
||||
|
||||
local i
|
||||
for (( i=1; i <= COMP_CWORD; i++ )); do
|
||||
|
||||
@ -78,6 +78,7 @@ _systemd_analyze() {
|
||||
[SECURITY]='security'
|
||||
[CONDITION]='condition'
|
||||
[INSPECT_ELF]='inspect-elf'
|
||||
[DLOPEN_METADATA]='dlopen-metadata'
|
||||
[PLOT]='plot'
|
||||
[ARCHITECTURES]='architectures'
|
||||
[FDSTORE]='fdstore'
|
||||
@ -212,6 +213,14 @@ _systemd_analyze() {
|
||||
compopt -o filenames
|
||||
fi
|
||||
|
||||
elif __contains_word "$verb" ${VERBS[DLOPEN_METADATA]}; then
|
||||
if [[ $cur = -* ]]; then
|
||||
comps='--help --version --json=off --json=pretty --json=short'
|
||||
else
|
||||
comps=$( compgen -A file -- "$cur" )
|
||||
compopt -o filenames
|
||||
fi
|
||||
|
||||
elif __contains_word "$verb" ${VERBS[PLOT]}; then
|
||||
if [[ $cur = -* ]]; then
|
||||
comps='--help --version --system --user --global --no-pager --json=off --json=pretty --json=short --table --no-legend --scale-svg --detailed'
|
||||
|
||||
@ -52,6 +52,7 @@ local -a args=(
|
||||
'--machine=[Execute the operation on a local container]:machine:_sd_machines'
|
||||
{-h,--help}'[Show the help text and exit]'
|
||||
'--version[Print a short version string and exit]'
|
||||
'--empower[Give privileges to selected or current user]'
|
||||
)
|
||||
|
||||
_arguments -S $args '*:: :{_normal -p $service}'
|
||||
|
||||
@ -79,6 +79,7 @@
|
||||
'timespan:Parse a systemd syntax timespan'
|
||||
'security:Analyze security settings of a service'
|
||||
'inspect-elf:Parse and print ELF package metadata'
|
||||
'dlopen-metadata:Parse and print ELF dlopen metadata'
|
||||
'has-tpm2:Report whether TPM2 support is available'
|
||||
'transient-settings:List transient settings for unit types'
|
||||
# log-level, log-target, service-watchdogs have been deprecated
|
||||
|
||||
@ -1277,7 +1277,6 @@ static int setup_pam(
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
char ***env, /* updated on success */
|
||||
const int fds[], size_t n_fds,
|
||||
bool needs_sandboxing,
|
||||
int exec_fd) {
|
||||
|
||||
@ -1307,7 +1306,6 @@ static int setup_pam(
|
||||
assert(user);
|
||||
assert(uid_is_valid(uid));
|
||||
assert(gid_is_valid(gid));
|
||||
assert(fds || n_fds == 0);
|
||||
assert(env);
|
||||
|
||||
/* We set up PAM in the parent process, then fork. The child will then stay around until killed via
|
||||
@ -1393,7 +1391,7 @@ static int setup_pam(
|
||||
|
||||
/* Make sure we don't keep open the passed fds in this child. We assume that otherwise only
|
||||
* those fds are open here that have been opened by PAM. */
|
||||
(void) close_many(fds, n_fds);
|
||||
(void) close_many(params->fds, params->n_socket_fds + params->n_stashed_fds);
|
||||
|
||||
/* Also close the 'exec_fd' in the child, since the service manager waits for the EOF induced
|
||||
* by the execve() to wait for completion, and if we'd keep the fd open here in the child
|
||||
@ -1992,7 +1990,6 @@ static int build_environment(
|
||||
const ExecContext *c,
|
||||
const ExecParameters *p,
|
||||
const CGroupContext *cgroup_context,
|
||||
size_t n_fds,
|
||||
const char *home,
|
||||
const char *username,
|
||||
const char *shell,
|
||||
@ -2017,7 +2014,7 @@ static int build_environment(
|
||||
if (!our_env)
|
||||
return -ENOMEM;
|
||||
|
||||
if (n_fds > 0) {
|
||||
if (p->n_socket_fds + p->n_stashed_fds > 0) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
|
||||
if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid_cached()) < 0)
|
||||
@ -2031,7 +2028,7 @@ static int build_environment(
|
||||
our_env[n_env++] = x;
|
||||
}
|
||||
|
||||
if (asprintf(&x, "LISTEN_FDS=%zu", n_fds) < 0)
|
||||
if (asprintf(&x, "LISTEN_FDS=%zu", p->n_socket_fds + p->n_stashed_fds) < 0)
|
||||
return -ENOMEM;
|
||||
our_env[n_env++] = x;
|
||||
|
||||
@ -4327,12 +4324,11 @@ static int exec_context_cpu_affinity_from_numa(const ExecContext *c, CPUSet *ret
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_shifted_fd(int *fds, size_t fds_size, size_t *n_fds, int *fd) {
|
||||
static int add_shifted_fd(int **fds, size_t *n_fds, int *fd) {
|
||||
int r;
|
||||
|
||||
assert(fds);
|
||||
assert(n_fds);
|
||||
assert(*n_fds < fds_size);
|
||||
assert(fd);
|
||||
|
||||
if (*fd < 0)
|
||||
@ -4349,7 +4345,10 @@ static int add_shifted_fd(int *fds, size_t fds_size, size_t *n_fds, int *fd) {
|
||||
close_and_replace(*fd, r);
|
||||
}
|
||||
|
||||
fds[(*n_fds)++] = *fd;
|
||||
if (!GREEDY_REALLOC(*fds, *n_fds + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
(*fds)[(*n_fds)++] = *fd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -4426,9 +4425,8 @@ static int get_open_file_fd(const OpenFile *of) {
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
|
||||
static int collect_open_file_fds(ExecParameters *p, size_t *n_fds) {
|
||||
static int collect_open_file_fds(ExecParameters *p) {
|
||||
assert(p);
|
||||
assert(n_fds);
|
||||
|
||||
LIST_FOREACH(open_files, of, p->open_files) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
@ -4446,13 +4444,13 @@ static int collect_open_file_fds(ExecParameters *p, size_t *n_fds) {
|
||||
return log_error_errno(fd, "Failed to get OpenFile= file descriptor for '%s': %m", of->path);
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(p->fds, *n_fds + 1))
|
||||
if (!GREEDY_REALLOC(p->fds, p->n_stashed_fds + 1))
|
||||
return log_oom();
|
||||
|
||||
if (strv_extend(&p->fd_names, of->fdname) < 0)
|
||||
return log_oom();
|
||||
|
||||
p->fds[(*n_fds)++] = TAKE_FD(fd);
|
||||
p->fds[p->n_stashed_fds++] = TAKE_FD(fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -4745,9 +4743,8 @@ static int exec_context_named_iofds(
|
||||
const ExecParameters *p,
|
||||
int named_iofds[static 3]) {
|
||||
|
||||
const char *stdio_fdname[3];
|
||||
size_t targets;
|
||||
const char* stdio_fdname[3];
|
||||
size_t n_fds;
|
||||
|
||||
assert(c);
|
||||
assert(p);
|
||||
@ -4760,12 +4757,11 @@ static int exec_context_named_iofds(
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
stdio_fdname[i] = exec_context_fdname(c, i);
|
||||
|
||||
n_fds = p->n_storage_fds + p->n_socket_fds + p->n_extra_fds;
|
||||
|
||||
for (size_t i = 0; i < n_fds && targets > 0; i++)
|
||||
/* Note that socket fds are always placed at the beginning of the fds array, no need for extra
|
||||
* manipulation. */
|
||||
for (size_t i = 0; i < p->n_socket_fds && targets > 0; i++)
|
||||
if (named_iofds[STDIN_FILENO] < 0 &&
|
||||
c->std_input == EXEC_INPUT_NAMED_FD &&
|
||||
stdio_fdname[STDIN_FILENO] &&
|
||||
streq(p->fd_names[i], stdio_fdname[STDIN_FILENO])) {
|
||||
|
||||
named_iofds[STDIN_FILENO] = p->fds[i];
|
||||
@ -4773,7 +4769,6 @@ static int exec_context_named_iofds(
|
||||
|
||||
} else if (named_iofds[STDOUT_FILENO] < 0 &&
|
||||
c->std_output == EXEC_OUTPUT_NAMED_FD &&
|
||||
stdio_fdname[STDOUT_FILENO] &&
|
||||
streq(p->fd_names[i], stdio_fdname[STDOUT_FILENO])) {
|
||||
|
||||
named_iofds[STDOUT_FILENO] = p->fds[i];
|
||||
@ -4781,7 +4776,6 @@ static int exec_context_named_iofds(
|
||||
|
||||
} else if (named_iofds[STDERR_FILENO] < 0 &&
|
||||
c->std_error == EXEC_OUTPUT_NAMED_FD &&
|
||||
stdio_fdname[STDERR_FILENO] &&
|
||||
streq(p->fd_names[i], stdio_fdname[STDERR_FILENO])) {
|
||||
|
||||
named_iofds[STDERR_FILENO] = p->fds[i];
|
||||
@ -5032,14 +5026,11 @@ int exec_invoke(
|
||||
gid_t saved_gid = getgid();
|
||||
uid_t uid = UID_INVALID;
|
||||
gid_t gid = GID_INVALID;
|
||||
size_t n_fds, /* fds to pass to the child */
|
||||
n_keep_fds; /* total number of fds not to close */
|
||||
int secure_bits;
|
||||
_cleanup_free_ gid_t *gids = NULL, *gids_after_pam = NULL;
|
||||
int ngids = 0, ngids_after_pam = 0;
|
||||
int socket_fd = -EBADF, named_iofds[3] = EBADF_TRIPLET;
|
||||
_cleanup_close_ int bpffs_socket_fd = -EBADF, bpffs_errno_pipe = -EBADF;
|
||||
size_t n_storage_fds, n_socket_fds, n_extra_fds;
|
||||
int named_iofds[3] = EBADF_TRIPLET;
|
||||
_cleanup_close_ int socket_fd = -EBADF, bpffs_socket_fd = -EBADF, bpffs_errno_pipe = -EBADF;
|
||||
_cleanup_(pidref_done_sigkill_wait) PidRef bpffs_pidref = PIDREF_NULL;
|
||||
|
||||
assert(command);
|
||||
@ -5057,30 +5048,30 @@ int exec_invoke(
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid command line arguments.");
|
||||
}
|
||||
|
||||
rename_process_from_path(command->path);
|
||||
|
||||
if (context->std_input == EXEC_INPUT_SOCKET ||
|
||||
context->std_output == EXEC_OUTPUT_SOCKET ||
|
||||
context->std_error == EXEC_OUTPUT_SOCKET) {
|
||||
|
||||
if (params->n_socket_fds > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got more than one socket.");
|
||||
if (params->n_socket_fds != 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected exactly one socket, got %zu.",
|
||||
params->n_socket_fds);
|
||||
|
||||
if (params->n_socket_fds == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got no socket.");
|
||||
socket_fd = TAKE_FD(params->fds[0]);
|
||||
free(params->fd_names[0]);
|
||||
params->n_socket_fds = 0;
|
||||
|
||||
socket_fd = params->fds[0];
|
||||
n_storage_fds = n_socket_fds = n_extra_fds = 0;
|
||||
} else {
|
||||
n_socket_fds = params->n_socket_fds;
|
||||
n_storage_fds = params->n_storage_fds;
|
||||
n_extra_fds = params->n_extra_fds;
|
||||
memmove(params->fds, params->fds + 1, params->n_stashed_fds * sizeof(int));
|
||||
memmove(params->fd_names, params->fd_names + 1, params->n_stashed_fds * sizeof(char*));
|
||||
params->fd_names[params->n_stashed_fds] = NULL;
|
||||
}
|
||||
n_fds = n_socket_fds + n_storage_fds + n_extra_fds;
|
||||
|
||||
r = exec_context_named_iofds(context, params, named_iofds);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_FDS;
|
||||
return log_error_errno(r, "Failed to load a named file descriptor: %m");
|
||||
|
||||
rename_process_from_path(command->path);
|
||||
}
|
||||
|
||||
/* We reset exactly these signals, since they are the only ones we set to SIG_IGN in the main
|
||||
* daemon. All others we leave untouched because we set them to SIG_DFL or a valid handler initially,
|
||||
@ -5112,30 +5103,33 @@ int exec_invoke(
|
||||
/* In case anything used libc syslog(), close this here, too */
|
||||
closelog();
|
||||
|
||||
r = collect_open_file_fds(params, &n_fds);
|
||||
r = collect_open_file_fds(params);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_FDS;
|
||||
return log_error_errno(r, "Failed to get OpenFile= file descriptors: %m");
|
||||
}
|
||||
|
||||
int keep_fds[n_fds + 4];
|
||||
memcpy_safe(keep_fds, params->fds, n_fds * sizeof(int));
|
||||
n_keep_fds = n_fds;
|
||||
size_t n_keep_fds = params->n_socket_fds + params->n_stashed_fds;
|
||||
_cleanup_free_ int *keep_fds = newdup(int, params->fds, n_keep_fds);
|
||||
if (!keep_fds) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, ¶ms->exec_fd);
|
||||
r = add_shifted_fd(&keep_fds, &n_keep_fds, ¶ms->exec_fd);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_FDS;
|
||||
return log_error_errno(r, "Failed to collect shifted fd: %m");
|
||||
}
|
||||
|
||||
r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, ¶ms->handoff_timestamp_fd);
|
||||
r = add_shifted_fd(&keep_fds, &n_keep_fds, ¶ms->handoff_timestamp_fd);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_FDS;
|
||||
return log_error_errno(r, "Failed to collect shifted fd: %m");
|
||||
}
|
||||
|
||||
#if HAVE_LIBBPF
|
||||
r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, ¶ms->bpf_restrict_fs_map_fd);
|
||||
r = add_shifted_fd(&keep_fds, &n_keep_fds, ¶ms->bpf_restrict_fs_map_fd);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_FDS;
|
||||
return log_error_errno(r, "Failed to collect shifted fd: %m");
|
||||
@ -5618,7 +5612,6 @@ int exec_invoke(
|
||||
context,
|
||||
params,
|
||||
cgroup_context,
|
||||
n_fds,
|
||||
pwent_home,
|
||||
username,
|
||||
shell,
|
||||
@ -5732,7 +5725,7 @@ int exec_invoke(
|
||||
|
||||
/* All fds passed in the fds array will be closed in the pam child process. */
|
||||
r = setup_pam(context, cgroup_context, params, username, uid, gid, &accum_env,
|
||||
params->fds, n_fds, needs_sandboxing, params->exec_fd);
|
||||
needs_sandboxing, params->exec_fd);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_PAM;
|
||||
return log_error_errno(r, "Failed to set up PAM session: %m");
|
||||
@ -5925,7 +5918,7 @@ int exec_invoke(
|
||||
return r != -ENOMEM && FLAGS_SET(command->flags, EXEC_COMMAND_IGNORE_FAILURE) ? 1 : r;
|
||||
}
|
||||
|
||||
r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, &executable_fd);
|
||||
r = add_shifted_fd(&keep_fds, &n_keep_fds, &executable_fd);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_FDS;
|
||||
return log_error_errno(r, "Failed to collect shifted fd: %m");
|
||||
@ -5966,9 +5959,10 @@ int exec_invoke(
|
||||
|
||||
r = close_all_fds(keep_fds, n_keep_fds);
|
||||
if (r >= 0)
|
||||
r = pack_fds(params->fds, n_fds);
|
||||
r = pack_fds(params->fds, params->n_socket_fds + params->n_stashed_fds);
|
||||
if (r >= 0)
|
||||
r = flag_fds(params->fds, n_socket_fds, n_fds, context->non_blocking);
|
||||
r = flag_fds(params->fds, params->n_socket_fds, params->n_socket_fds + params->n_stashed_fds,
|
||||
context->non_blocking);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_FDS;
|
||||
return log_error_errno(r, "Failed to adjust passed file descriptors: %m");
|
||||
|
||||
@ -1090,27 +1090,21 @@ static int exec_parameters_serialize(const ExecParameters *p, const ExecContext
|
||||
return r;
|
||||
}
|
||||
|
||||
if (p->n_storage_fds > 0) {
|
||||
r = serialize_item_format(f, "exec-parameters-n-storage-fds", "%zu", p->n_storage_fds);
|
||||
if (p->n_stashed_fds > 0) {
|
||||
r = serialize_item_format(f, "exec-parameters-n-stashed-fds", "%zu", p->n_stashed_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (p->n_extra_fds > 0) {
|
||||
r = serialize_item_format(f, "exec-parameters-n-extra-fds", "%zu", p->n_extra_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = serialize_fd_many(f, fds, "exec-parameters-fds", p->fds, p->n_socket_fds + p->n_stashed_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = serialize_fd_many(f, fds, "exec-parameters-fds", p->fds, p->n_socket_fds + p->n_storage_fds + p->n_extra_fds);
|
||||
r = serialize_strv(f, "exec-parameters-fd-names", p->fd_names);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = serialize_strv(f, "exec-parameters-fd-names", p->fd_names);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (p->flags != 0) {
|
||||
r = serialize_item_format(f, "exec-parameters-flags", "%u", (unsigned) p->flags);
|
||||
if (r < 0)
|
||||
@ -1121,12 +1115,6 @@ static int exec_parameters_serialize(const ExecParameters *p, const ExecContext
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (p->cgroup_supported != 0) {
|
||||
r = serialize_item_format(f, "exec-parameters-cgroup-supported", "%u", (unsigned) p->cgroup_supported);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = serialize_item(f, "exec-parameters-cgroup-path", p->cgroup_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1289,47 +1277,37 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) {
|
||||
|
||||
if (p->n_socket_fds > nr_open)
|
||||
return -EINVAL; /* too many, someone is playing games with us */
|
||||
} else if ((val = startswith(l, "exec-parameters-n-storage-fds="))) {
|
||||
} else if ((val = startswith(l, "exec-parameters-n-stashed-fds="))) {
|
||||
if (p->fds)
|
||||
return -EINVAL; /* Already received */
|
||||
|
||||
r = safe_atozu(val, &p->n_storage_fds);
|
||||
r = safe_atozu(val, &p->n_stashed_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (p->n_storage_fds > nr_open)
|
||||
return -EINVAL; /* too many, someone is playing games with us */
|
||||
} else if ((val = startswith(l, "exec-parameters-n-extra-fds="))) {
|
||||
if (p->fds)
|
||||
return -EINVAL; /* Already received */
|
||||
|
||||
r = safe_atozu(val, &p->n_extra_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (p->n_extra_fds > nr_open)
|
||||
if (p->n_stashed_fds > nr_open)
|
||||
return -EINVAL; /* too many, someone is playing games with us */
|
||||
} else if ((val = startswith(l, "exec-parameters-fds="))) {
|
||||
if (p->n_socket_fds + p->n_storage_fds + p->n_extra_fds == 0)
|
||||
if (p->n_socket_fds + p->n_stashed_fds == 0)
|
||||
return log_warning_errno(
|
||||
SYNTHETIC_ERRNO(EINVAL),
|
||||
"Got exec-parameters-fds= without "
|
||||
"prior exec-parameters-n-socket-fds= or exec-parameters-n-storage-fds= or exec-parameters-n-extra-fds=");
|
||||
if (p->n_socket_fds + p->n_storage_fds + p->n_extra_fds > nr_open)
|
||||
"prior exec-parameters-n-socket-fds= or exec-parameters-n-stashed-fds=");
|
||||
if (p->n_socket_fds + p->n_stashed_fds > nr_open)
|
||||
return -EINVAL; /* too many, someone is playing games with us */
|
||||
|
||||
if (p->fds)
|
||||
return -EINVAL; /* duplicated */
|
||||
|
||||
p->fds = new(int, p->n_socket_fds + p->n_storage_fds + p->n_extra_fds);
|
||||
p->fds = new(int, p->n_socket_fds + p->n_stashed_fds);
|
||||
if (!p->fds)
|
||||
return log_oom_debug();
|
||||
|
||||
/* Ensure we don't leave any FD uninitialized on error, it makes the fuzzer sad */
|
||||
FOREACH_ARRAY(i, p->fds, p->n_socket_fds + p->n_storage_fds + p->n_extra_fds)
|
||||
FOREACH_ARRAY(i, p->fds, p->n_socket_fds + p->n_stashed_fds)
|
||||
*i = -EBADF;
|
||||
|
||||
r = deserialize_fd_many(fds, val, p->n_socket_fds + p->n_storage_fds + p->n_extra_fds, p->fds);
|
||||
r = deserialize_fd_many(fds, val, p->n_socket_fds + p->n_stashed_fds, p->fds);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
@ -1350,13 +1328,6 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) {
|
||||
return r;
|
||||
|
||||
p->selinux_context_net = r;
|
||||
} else if ((val = startswith(l, "exec-parameters-cgroup-supported="))) {
|
||||
unsigned cgroup_supported;
|
||||
|
||||
r = safe_atou(val, &cgroup_supported);
|
||||
if (r < 0)
|
||||
return r;
|
||||
p->cgroup_supported = cgroup_supported;
|
||||
} else if ((val = startswith(l, "exec-parameters-cgroup-path="))) {
|
||||
r = free_and_strdup(&p->cgroup_path, val);
|
||||
if (r < 0)
|
||||
@ -1534,9 +1505,9 @@ static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) {
|
||||
log_warning("Failed to parse serialized line, ignoring: %s", l);
|
||||
}
|
||||
|
||||
/* Bail out if we got exec-parameters-n-{socket/storage}-fds= but no corresponding
|
||||
/* Bail out if we got exec-parameters-n-{socket/stashed}-fds= but no corresponding
|
||||
* exec-parameters-fds= */
|
||||
if (p->n_socket_fds + p->n_storage_fds > 0 && !p->fds)
|
||||
if (p->n_socket_fds + p->n_stashed_fds > 0 && !p->fds)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
@ -486,8 +486,8 @@ int exec_spawn(
|
||||
assert(command);
|
||||
assert(context);
|
||||
assert(params);
|
||||
assert(!params->fds || FLAGS_SET(params->flags, EXEC_PASS_FDS));
|
||||
assert(params->fds || (params->n_socket_fds + params->n_storage_fds + params->n_extra_fds == 0));
|
||||
assert(params->fds || (params->n_socket_fds + params->n_stashed_fds == 0 && !params->fd_names));
|
||||
assert(params->n_stashed_fds == 0 || FLAGS_SET(params->flags, EXEC_PASS_FDS));
|
||||
assert(!params->files_env); /* We fill this field, ensure it comes NULL-initialized to us */
|
||||
assert(ret);
|
||||
|
||||
@ -1048,7 +1048,6 @@ void exec_params_dump(const ExecParameters *p, FILE* f, const char *prefix) {
|
||||
"%sRuntimeScope: %s\n"
|
||||
"%sExecFlags: %u\n"
|
||||
"%sSELinuxContextNetwork: %s\n"
|
||||
"%sCgroupSupportedMask: %u\n"
|
||||
"%sCgroupPath: %s\n"
|
||||
"%sCrededentialsDirectory: %s\n"
|
||||
"%sEncryptedCredentialsDirectory: %s\n"
|
||||
@ -1061,7 +1060,6 @@ void exec_params_dump(const ExecParameters *p, FILE* f, const char *prefix) {
|
||||
prefix, runtime_scope_to_string(p->runtime_scope),
|
||||
prefix, p->flags,
|
||||
prefix, yes_no(p->selinux_context_net),
|
||||
prefix, p->cgroup_supported,
|
||||
prefix, p->cgroup_path,
|
||||
prefix, strempty(p->received_credentials_directory),
|
||||
prefix, strempty(p->received_encrypted_credentials_directory),
|
||||
@ -2828,7 +2826,7 @@ void exec_params_deep_clear(ExecParameters *p) {
|
||||
* to be fully cleaned up to make sanitizers and analyzers happy, as opposed as the shallow clean
|
||||
* function above. */
|
||||
|
||||
close_many_unset(p->fds, p->n_socket_fds + p->n_storage_fds + p->n_extra_fds);
|
||||
close_many_unset(p->fds, p->n_socket_fds + p->n_stashed_fds);
|
||||
|
||||
p->cgroup_path = mfree(p->cgroup_path);
|
||||
|
||||
|
||||
@ -391,18 +391,16 @@ typedef enum ExecFlags {
|
||||
typedef struct ExecParameters {
|
||||
RuntimeScope runtime_scope;
|
||||
|
||||
ExecFlags flags;
|
||||
|
||||
char **environment;
|
||||
char **files_env;
|
||||
|
||||
int *fds;
|
||||
char **fd_names;
|
||||
size_t n_socket_fds;
|
||||
size_t n_storage_fds;
|
||||
size_t n_extra_fds;
|
||||
size_t n_stashed_fds;
|
||||
|
||||
ExecFlags flags;
|
||||
bool selinux_context_net:1;
|
||||
|
||||
CGroupMask cgroup_supported;
|
||||
char *cgroup_path;
|
||||
uint64_t cgroup_id;
|
||||
|
||||
@ -430,7 +428,6 @@ typedef struct ExecParameters {
|
||||
|
||||
char *fallback_smack_process_label;
|
||||
|
||||
char **files_env;
|
||||
int user_lookup_fd;
|
||||
int handoff_timestamp_fd;
|
||||
int pidref_transport_fd;
|
||||
@ -443,6 +440,7 @@ typedef struct ExecParameters {
|
||||
char invocation_id_string[SD_ID128_STRING_MAX];
|
||||
|
||||
bool debug_invocation;
|
||||
bool selinux_context_net;
|
||||
} ExecParameters;
|
||||
|
||||
#define EXEC_PARAMETERS_INIT(_flags) \
|
||||
@ -519,7 +517,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix);
|
||||
int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_root);
|
||||
int exec_context_destroy_mount_ns_dir(Unit *u);
|
||||
|
||||
const char* exec_context_fdname(const ExecContext *c, int fd_index);
|
||||
const char* exec_context_fdname(const ExecContext *c, int fd_index) _pure_;
|
||||
|
||||
bool exec_context_may_touch_console(const ExecContext *c);
|
||||
bool exec_context_maintains_privileges(const ExecContext *c);
|
||||
@ -585,8 +583,8 @@ void exec_runtime_clear(ExecRuntime *rt);
|
||||
int exec_params_needs_control_subcgroup(const ExecParameters *params);
|
||||
int exec_params_get_cgroup_path(const ExecParameters *params, const CGroupContext *c, const char *prefix, char **ret);
|
||||
void exec_params_shallow_clear(ExecParameters *p);
|
||||
void exec_params_dump(const ExecParameters *p, FILE* f, const char *prefix);
|
||||
void exec_params_deep_clear(ExecParameters *p);
|
||||
void exec_params_dump(const ExecParameters *p, FILE* f, const char *prefix);
|
||||
|
||||
bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c);
|
||||
|
||||
|
||||
@ -62,8 +62,8 @@ static void exec_fuzz_one(FILE *f, FDSet *fdset) {
|
||||
params.user_lookup_fd = -EBADF;
|
||||
params.bpf_restrict_fs_map_fd = -EBADF;
|
||||
if (!params.fds)
|
||||
params.n_socket_fds = params.n_storage_fds = params.n_extra_fds = 0;
|
||||
for (size_t i = 0; params.fds && i < params.n_socket_fds + params.n_storage_fds + params.n_extra_fds; i++)
|
||||
params.n_socket_fds = params.n_stashed_fds = 0;
|
||||
for (size_t i = 0; params.fds && i < params.n_socket_fds + params.n_stashed_fds; i++)
|
||||
params.fds[i] = -EBADF;
|
||||
|
||||
exec_command_done_array(&command, /* n= */ 1);
|
||||
|
||||
@ -1451,8 +1451,7 @@ static int service_collect_fds(
|
||||
int **fds,
|
||||
char ***fd_names,
|
||||
size_t *n_socket_fds,
|
||||
size_t *n_storage_fds,
|
||||
size_t *n_extra_fds) {
|
||||
size_t *n_stashed_fds) {
|
||||
|
||||
_cleanup_strv_free_ char **rfd_names = NULL;
|
||||
_cleanup_free_ int *rfds = NULL;
|
||||
@ -1463,8 +1462,6 @@ static int service_collect_fds(
|
||||
assert(fds);
|
||||
assert(fd_names);
|
||||
assert(n_socket_fds);
|
||||
assert(n_storage_fds);
|
||||
assert(n_extra_fds);
|
||||
|
||||
if (s->socket_fd >= 0) {
|
||||
Socket *sock = ASSERT_PTR(SOCKET(UNIT_DEREF(s->accept_socket)));
|
||||
@ -1511,7 +1508,7 @@ static int service_collect_fds(
|
||||
}
|
||||
}
|
||||
|
||||
if (s->n_fd_store + s->n_extra_fds > 0) {
|
||||
if (n_stashed_fds && s->n_fd_store + s->n_extra_fds > 0) {
|
||||
int *t = reallocarray(rfds, rn_socket_fds + s->n_fd_store + s->n_extra_fds, sizeof(int));
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
@ -1548,8 +1545,8 @@ static int service_collect_fds(
|
||||
*fds = TAKE_PTR(rfds);
|
||||
*fd_names = TAKE_PTR(rfd_names);
|
||||
*n_socket_fds = rn_socket_fds;
|
||||
*n_storage_fds = s->n_fd_store;
|
||||
*n_extra_fds = s->n_extra_fds;
|
||||
if (n_stashed_fds)
|
||||
*n_stashed_fds = s->n_fd_store + s->n_extra_fds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1733,25 +1730,32 @@ static int service_spawn_internal(
|
||||
exec_params.flags &= ~EXEC_APPLY_CHROOT;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(exec_params.flags, EXEC_PASS_FDS) ||
|
||||
s->exec_context.std_input == EXEC_INPUT_SOCKET ||
|
||||
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
|
||||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
|
||||
if (FLAGS_SET(exec_params.flags, EXEC_PASS_FDS)) {
|
||||
r = service_collect_fds(s,
|
||||
&exec_params.fds,
|
||||
&exec_params.fd_names,
|
||||
&exec_params.n_socket_fds,
|
||||
&exec_params.n_stashed_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_unit_debug(UNIT(s), "Passing %zu fds to service", exec_params.n_socket_fds + exec_params.n_stashed_fds);
|
||||
|
||||
exec_params.open_files = s->open_files;
|
||||
|
||||
} else if (IN_SET(s->exec_context.std_input, EXEC_INPUT_SOCKET, EXEC_INPUT_NAMED_FD) ||
|
||||
IN_SET(s->exec_context.std_output, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD) ||
|
||||
IN_SET(s->exec_context.std_error, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD)) {
|
||||
|
||||
r = service_collect_fds(s,
|
||||
&exec_params.fds,
|
||||
&exec_params.fd_names,
|
||||
&exec_params.n_socket_fds,
|
||||
&exec_params.n_storage_fds,
|
||||
&exec_params.n_extra_fds);
|
||||
/* n_stashed_fds = */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
exec_params.open_files = s->open_files;
|
||||
|
||||
exec_params.flags |= EXEC_PASS_FDS;
|
||||
|
||||
log_unit_debug(UNIT(s), "Passing %zu fds to service", exec_params.n_socket_fds + exec_params.n_storage_fds + exec_params.n_extra_fds);
|
||||
log_unit_debug(UNIT(s), "Passing %zu sockets to service", exec_params.n_socket_fds);
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(exec_params.flags, EXEC_IS_CONTROL) && s->type == SERVICE_EXEC) {
|
||||
|
||||
@ -2001,7 +2001,6 @@ static int socket_spawn(Socket *s, ExecCommand *c, PidRef *ret_pid) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
exec_params.flags |= EXEC_PASS_FDS;
|
||||
exec_params.fds = TAKE_PTR(fds);
|
||||
exec_params.fd_names = TAKE_PTR(fd_names);
|
||||
exec_params.n_socket_fds = n_fds;
|
||||
|
||||
@ -5506,7 +5506,6 @@ int unit_set_exec_params(Unit *u, ExecParameters *p) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p->cgroup_supported = u->manager->cgroup_supported;
|
||||
p->prefix = u->manager->prefix;
|
||||
SET_FLAG(p->flags, EXEC_PASS_LOG_UNIT|EXEC_CHOWN_DIRECTORIES, MANAGER_IS_SYSTEM(u->manager));
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tar-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "uid-classification.h"
|
||||
@ -1432,109 +1433,6 @@ static int mtree_print_item(
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
}
|
||||
|
||||
#if HAVE_LIBARCHIVE
|
||||
static int archive_item(
|
||||
RecurseDirEvent event,
|
||||
const char *path,
|
||||
int dir_fd,
|
||||
int inode_fd,
|
||||
const struct dirent *de,
|
||||
const struct statx *sx,
|
||||
void *userdata) {
|
||||
|
||||
struct archive *a = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
if (!IN_SET(event, RECURSE_DIR_ENTER, RECURSE_DIR_ENTRY))
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
|
||||
assert(inode_fd >= 0);
|
||||
assert(sx);
|
||||
|
||||
log_debug("Archiving %s\n", path);
|
||||
|
||||
_cleanup_(archive_entry_freep) struct archive_entry *entry = NULL;
|
||||
entry = sym_archive_entry_new();
|
||||
if (!entry)
|
||||
return log_oom();
|
||||
|
||||
assert(FLAGS_SET(sx->stx_mask, STATX_TYPE|STATX_MODE));
|
||||
sym_archive_entry_set_pathname(entry, path);
|
||||
sym_archive_entry_set_filetype(entry, sx->stx_mode);
|
||||
|
||||
if (!S_ISLNK(sx->stx_mode))
|
||||
sym_archive_entry_set_perm(entry, sx->stx_mode);
|
||||
|
||||
if (FLAGS_SET(sx->stx_mask, STATX_UID))
|
||||
sym_archive_entry_set_uid(entry, sx->stx_uid);
|
||||
if (FLAGS_SET(sx->stx_mask, STATX_GID))
|
||||
sym_archive_entry_set_gid(entry, sx->stx_gid);
|
||||
|
||||
if (S_ISREG(sx->stx_mode)) {
|
||||
if (!FLAGS_SET(sx->stx_mask, STATX_SIZE))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Unable to determine file size of '%s'.", path);
|
||||
|
||||
sym_archive_entry_set_size(entry, sx->stx_size);
|
||||
}
|
||||
|
||||
if (S_ISCHR(sx->stx_mode) || S_ISBLK(sx->stx_mode)) {
|
||||
sym_archive_entry_set_rdevmajor(entry, sx->stx_rdev_major);
|
||||
sym_archive_entry_set_rdevminor(entry, sx->stx_rdev_minor);
|
||||
}
|
||||
|
||||
/* We care about a modicum of reproducibility here, hence we don't save atime/btime here */
|
||||
if (FLAGS_SET(sx->stx_mask, STATX_MTIME))
|
||||
sym_archive_entry_set_mtime(entry, sx->stx_mtime.tv_sec, sx->stx_mtime.tv_nsec);
|
||||
if (FLAGS_SET(sx->stx_mask, STATX_CTIME))
|
||||
sym_archive_entry_set_ctime(entry, sx->stx_ctime.tv_sec, sx->stx_ctime.tv_nsec);
|
||||
|
||||
if (S_ISLNK(sx->stx_mode)) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
assert(dir_fd >= 0);
|
||||
assert(de);
|
||||
|
||||
r = readlinkat_malloc(dir_fd, de->d_name, &s);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read symlink target of '%s': %m", path);
|
||||
|
||||
sym_archive_entry_set_symlink(entry, s);
|
||||
}
|
||||
|
||||
if (sym_archive_write_header(a, entry) != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to write archive entry header: %s", sym_archive_error_string(a));
|
||||
|
||||
if (S_ISREG(sx->stx_mode)) {
|
||||
_cleanup_close_ int data_fd = -EBADF;
|
||||
|
||||
/* Convert the O_PATH fd in a proper fd */
|
||||
data_fd = fd_reopen(inode_fd, O_RDONLY|O_CLOEXEC);
|
||||
if (data_fd < 0)
|
||||
return log_error_errno(data_fd, "Failed to open '%s': %m", path);
|
||||
|
||||
for (;;) {
|
||||
char buffer[64*1024];
|
||||
ssize_t l;
|
||||
|
||||
l = read(data_fd, buffer, sizeof(buffer));
|
||||
if (l < 0)
|
||||
return log_error_errno(errno, "Failed to read '%s': %m", path);
|
||||
if (l == 0)
|
||||
break;
|
||||
|
||||
la_ssize_t k;
|
||||
k = sym_archive_write_data(a, buffer, l);
|
||||
if (k < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to write archive data: %s", sym_archive_error_string(a));
|
||||
}
|
||||
}
|
||||
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopDevice *d, int userns_fd) {
|
||||
_cleanup_(umount_and_freep) char *mounted_dir = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
@ -1736,56 +1634,34 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD
|
||||
|
||||
case ACTION_MAKE_ARCHIVE: {
|
||||
#if HAVE_LIBARCHIVE
|
||||
_cleanup_(unlink_and_freep) char *tar = NULL;
|
||||
_cleanup_close_ int dfd = -EBADF;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
dfd = open(root, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
|
||||
if (dfd < 0)
|
||||
return log_error_errno(errno, "Failed to open mount directory: %m");
|
||||
|
||||
_cleanup_(archive_write_freep) struct archive *a = sym_archive_write_new();
|
||||
if (!a)
|
||||
return log_oom();
|
||||
|
||||
if (arg_target)
|
||||
r = sym_archive_write_set_format_filter_by_ext(a, arg_target);
|
||||
else
|
||||
r = sym_archive_write_set_format_gnutar(a);
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to set libarchive output format: %s", sym_archive_error_string(a));
|
||||
|
||||
_cleanup_(unlink_and_freep) char *tar = NULL;
|
||||
_cleanup_close_ int tmp_fd = -EBADF;
|
||||
int output_fd;
|
||||
if (arg_target) {
|
||||
r = fopen_tmpfile_linkable(arg_target, O_WRONLY|O_CLOEXEC, &tar, &f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create target file '%s': %m", arg_target);
|
||||
tmp_fd = open_tmpfile_linkable(arg_target, O_WRONLY|O_CLOEXEC, &tar);
|
||||
if (tmp_fd < 0)
|
||||
return log_error_errno(tmp_fd, "Failed to create target file '%s': %m", arg_target);
|
||||
|
||||
r = sym_archive_write_open_FILE(a, f);
|
||||
output_fd = tmp_fd;
|
||||
} else {
|
||||
if (isatty_safe(STDOUT_FILENO))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Refusing to write archive to TTY.");
|
||||
|
||||
r = sym_archive_write_open_fd(a, STDOUT_FILENO);
|
||||
output_fd = STDOUT_FILENO;
|
||||
}
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to set libarchive output file: %s", sym_archive_error_string(a));
|
||||
|
||||
r = recurse_dir(dfd,
|
||||
".",
|
||||
STATX_TYPE|STATX_MODE|STATX_UID|STATX_GID|STATX_SIZE|STATX_ATIME|STATX_CTIME,
|
||||
UINT_MAX,
|
||||
RECURSE_DIR_SORT|RECURSE_DIR_INODE_FD|RECURSE_DIR_TOPLEVEL,
|
||||
archive_item,
|
||||
a);
|
||||
r = tar_c(dfd, output_fd, arg_target, /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make archive: %m");
|
||||
|
||||
r = sym_archive_write_close(a);
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to finish writing archive: %s", sym_archive_error_string(a));
|
||||
return r;
|
||||
|
||||
if (arg_target) {
|
||||
r = flink_tmpfile(f, tar, arg_target, LINK_TMPFILE_REPLACE);
|
||||
r = link_tmpfile(tmp_fd, tar, arg_target, LINK_TMPFILE_REPLACE);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to move archive file into place: %m");
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "btrfs-util.h"
|
||||
#include "dissect-image.h"
|
||||
#include "export-tar.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
@ -27,11 +28,15 @@ typedef struct TarExport {
|
||||
TarExportFinished on_finished;
|
||||
void *userdata;
|
||||
|
||||
ImportFlags flags;
|
||||
|
||||
char *path;
|
||||
char *temp_path;
|
||||
|
||||
int output_fd;
|
||||
int tar_fd;
|
||||
int output_fd; /* compressed tar file in the fs */
|
||||
int tar_fd; /* uncompressed tar stream coming from child doing the libarchive loop */
|
||||
int tree_fd; /* directory fd of the tree to set up */
|
||||
int userns_fd;
|
||||
|
||||
ImportCompress compress;
|
||||
|
||||
@ -98,6 +103,8 @@ int tar_export_new(
|
||||
*e = (TarExport) {
|
||||
.output_fd = -EBADF,
|
||||
.tar_fd = -EBADF,
|
||||
.tree_fd = -EBADF,
|
||||
.userns_fd = -EBADF,
|
||||
.on_finished = on_finished,
|
||||
.userdata = userdata,
|
||||
.quota_referenced = UINT64_MAX,
|
||||
@ -271,7 +278,13 @@ static int tar_export_on_defer(sd_event_source *s, void *userdata) {
|
||||
return tar_export_process(i);
|
||||
}
|
||||
|
||||
int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType compress) {
|
||||
int tar_export_start(
|
||||
TarExport *e,
|
||||
const char *path,
|
||||
int fd,
|
||||
ImportCompressType compress,
|
||||
ImportFlags flags) {
|
||||
|
||||
_cleanup_close_ int sfd = -EBADF;
|
||||
int r;
|
||||
|
||||
@ -299,6 +312,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
e->flags = flags;
|
||||
e->quota_referenced = UINT64_MAX;
|
||||
|
||||
if (btrfs_might_be_subvol(&e->st)) {
|
||||
@ -337,7 +351,33 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
e->tar_fd = import_fork_tar_c(e->temp_path ?: e->path, &e->tar_pid);
|
||||
const char *p = e->temp_path ?: e->path;
|
||||
|
||||
if (FLAGS_SET(e->flags, IMPORT_FOREIGN_UID)) {
|
||||
r = import_make_foreign_userns(&e->userns_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_close_ int directory_fd = open(p, O_DIRECTORY|O_CLOEXEC|O_PATH);
|
||||
if (directory_fd < 0)
|
||||
return log_error_errno(r, "Failed to open '%s': %m", p);
|
||||
|
||||
_cleanup_close_ int mapped_fd = -EBADF;
|
||||
r = mountfsd_mount_directory_fd(directory_fd, e->userns_fd, DISSECT_IMAGE_FOREIGN_UID, &mapped_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Drop O_PATH */
|
||||
e->tree_fd = fd_reopen(mapped_fd, O_DIRECTORY|O_CLOEXEC);
|
||||
if (e->tree_fd < 0)
|
||||
return log_error_errno(errno, "Failed to re-open mapped '%s': %m", p);
|
||||
} else {
|
||||
e->tree_fd = open(p, O_DIRECTORY|O_CLOEXEC);
|
||||
if (e->tree_fd < 0)
|
||||
return log_error_errno(errno, "Failed to open '%s': %m", p);
|
||||
}
|
||||
|
||||
e->tar_fd = import_fork_tar_c(e->tree_fd, e->userns_fd, &e->tar_pid);
|
||||
if (e->tar_fd < 0) {
|
||||
e->output_event_source = sd_event_source_unref(e->output_event_source);
|
||||
return e->tar_fd;
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "shared-forward.h"
|
||||
#include "import-common.h"
|
||||
#include "import-compress.h"
|
||||
#include "shared-forward.h"
|
||||
|
||||
typedef struct TarExport TarExport;
|
||||
|
||||
@ -13,4 +14,4 @@ TarExport* tar_export_unref(TarExport *export);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(TarExport*, tar_export_unref);
|
||||
|
||||
int tar_export_start(TarExport *export, const char *path, int fd, ImportCompressType compress);
|
||||
int tar_export_start(TarExport *export, const char *path, int fd, ImportCompressType compress, ImportFlags flags);
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "terminal-util.h"
|
||||
#include "verbs.h"
|
||||
|
||||
static ImportFlags arg_import_flags = 0;
|
||||
static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
|
||||
static ImageClass arg_class = IMAGE_MACHINE;
|
||||
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||
@ -111,7 +112,12 @@ static int export_tar(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate exporter: %m");
|
||||
|
||||
r = tar_export_start(export, local, fd, arg_compress);
|
||||
r = tar_export_start(
|
||||
export,
|
||||
local,
|
||||
fd,
|
||||
arg_compress,
|
||||
arg_import_flags & IMPORT_FLAGS_MASK_TAR);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to export image: %m");
|
||||
|
||||
@ -283,6 +289,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (arg_runtime_scope == RUNTIME_SCOPE_USER)
|
||||
arg_import_flags |= IMPORT_FOREIGN_UID;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -90,62 +90,61 @@ int import_fork_tar_x(int tree_fd, int userns_fd, PidRef *ret_pid) {
|
||||
return TAKE_FD(pipefd[1]);
|
||||
}
|
||||
|
||||
int import_fork_tar_c(const char *path, PidRef *ret) {
|
||||
_cleanup_close_pair_ int pipefd[2] = EBADF_PAIR;
|
||||
_cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
|
||||
bool use_selinux;
|
||||
int import_fork_tar_c(int tree_fd, int userns_fd, PidRef *ret_pid) {
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(ret);
|
||||
assert(tree_fd >= 0);
|
||||
assert(ret_pid);
|
||||
|
||||
r = dlopen_libarchive();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TarFlags flags = mac_selinux_use() ? TAR_SELINUX : 0;
|
||||
|
||||
_cleanup_close_pair_ int pipefd[2] = EBADF_PAIR;
|
||||
if (pipe2(pipefd, O_CLOEXEC) < 0)
|
||||
return log_error_errno(errno, "Failed to create pipe for tar: %m");
|
||||
|
||||
(void) fcntl(pipefd[0], F_SETPIPE_SZ, IMPORT_BUFFER_SIZE);
|
||||
|
||||
use_selinux = mac_selinux_use();
|
||||
|
||||
r = pidref_safe_fork_full(
|
||||
"(tar)",
|
||||
(int[]) { -EBADF, pipefd[1], STDERR_FILENO },
|
||||
NULL, 0,
|
||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG,
|
||||
&pid);
|
||||
"tar-c",
|
||||
/* stdio_fds= */ NULL,
|
||||
(int[]) { tree_fd, pipefd[1], userns_fd }, userns_fd >= 0 ? 3 : 2,
|
||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_REOPEN_LOG,
|
||||
ret_pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
const char *cmdline[] = {
|
||||
"tar",
|
||||
"-C", path,
|
||||
"-c",
|
||||
"--xattrs",
|
||||
"--xattrs-include=*",
|
||||
use_selinux ? "--selinux" : "--no-selinux",
|
||||
".",
|
||||
NULL
|
||||
};
|
||||
|
||||
uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
|
||||
static const uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
|
||||
|
||||
/* Child */
|
||||
|
||||
if (userns_fd >= 0) {
|
||||
r = detach_mount_namespace_userns(userns_fd);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to join user namespace: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (unshare(CLONE_NEWNET) < 0)
|
||||
log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
|
||||
log_debug_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
|
||||
|
||||
r = capability_bounding_set_drop(retain, true);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
|
||||
log_debug_errno(r, "Failed to drop capabilities, ignoring: %m");
|
||||
|
||||
execvp("gtar", (char* const*) cmdline);
|
||||
execvp("tar", (char* const*) cmdline);
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
|
||||
log_warning_errno(errno, "Failed to enable PR_SET_NO_NEW_PRIVS, ignoring: %m");
|
||||
|
||||
log_error_errno(errno, "Failed to execute tar: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
if (tar_c(tree_fd, pipefd[1], /* filename= */ NULL, flags) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
*ret = TAKE_PIDREF(pid);
|
||||
|
||||
return TAKE_FD(pipefd[0]);
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ typedef enum ImportFlags {
|
||||
_IMPORT_FLAGS_INVALID = -EINVAL,
|
||||
} ImportFlags;
|
||||
|
||||
int import_fork_tar_c(const char *path, PidRef *ret);
|
||||
int import_fork_tar_c(int tree_fd, int userns_fd, PidRef *ret_pid);
|
||||
int import_fork_tar_x(int tree_fd, int userns_fd, PidRef *ret_pid);
|
||||
|
||||
int import_mangle_os_tree(const char *path);
|
||||
|
||||
@ -118,7 +118,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
|
||||
(UINT32_C(1) << TPM2_PCR_BOOT_LOADER_CONFIG) | \
|
||||
(UINT32_C(1) << TPM2_PCR_SECURE_BOOT_POLICY) | \
|
||||
(UINT32_C(1) << TPM2_PCR_KERNEL_BOOT) | \
|
||||
(UINT32_C(1) << TPM2_PCR_KERNEL_CONFIG) | \
|
||||
/* Note: we do not add PCR12/TPM2_PCR_KERNEL_CONFIG here, since our pcrlock policy ends up in there, and this would hence result in a conceptual loop */ \
|
||||
(UINT32_C(1) << TPM2_PCR_SYSEXTS) | \
|
||||
(UINT32_C(1) << TPM2_PCR_SHIM_POLICY) | \
|
||||
(UINT32_C(1) << TPM2_PCR_SYSTEM_IDENTITY))
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "bus-util.h"
|
||||
#include "bus-wait-for-jobs.h"
|
||||
#include "calendarspec.h"
|
||||
#include "capability-util.h"
|
||||
#include "capsule-util.h"
|
||||
#include "chase.h"
|
||||
#include "env-util.h"
|
||||
@ -117,6 +118,7 @@ static char *arg_shell_prompt_prefix = NULL;
|
||||
static int arg_lightweight = -1;
|
||||
static char *arg_area = NULL;
|
||||
static bool arg_via_shell = false;
|
||||
static bool arg_empower = false;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
|
||||
@ -244,6 +246,7 @@ static int help_sudo_mode(void) {
|
||||
" --lightweight=BOOLEAN Control whether to register a session with service manager\n"
|
||||
" or without\n"
|
||||
" --area=AREA Home area to log into\n"
|
||||
" --empower Give privileges to selected or current user\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
@ -253,11 +256,15 @@ static int help_sudo_mode(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool become_root(void) {
|
||||
return !arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0");
|
||||
}
|
||||
|
||||
static bool privileged_execution(void) {
|
||||
if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
|
||||
return false;
|
||||
|
||||
return !arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0");
|
||||
return become_root() || arg_empower;
|
||||
}
|
||||
|
||||
static int add_timer_property(const char *name, const char *val) {
|
||||
@ -859,6 +866,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
ARG_LIGHTWEIGHT,
|
||||
ARG_AREA,
|
||||
ARG_VIA_SHELL,
|
||||
ARG_EMPOWER,
|
||||
};
|
||||
|
||||
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
||||
@ -888,6 +896,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
{ "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
|
||||
{ "lightweight", required_argument, NULL, ARG_LIGHTWEIGHT },
|
||||
{ "area", required_argument, NULL, ARG_AREA },
|
||||
{ "empower", no_argument, NULL, ARG_EMPOWER },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -1027,6 +1036,10 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
arg_via_shell = true;
|
||||
break;
|
||||
|
||||
case ARG_EMPOWER:
|
||||
arg_empower = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -1034,9 +1047,13 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (!arg_exec_user && arg_area) {
|
||||
if (!arg_exec_user && (arg_area || arg_empower)) {
|
||||
/* If the user specifies --area= but not --user= then consider this an area switch request,
|
||||
* and default to logging into our own account */
|
||||
* and default to logging into our own account.
|
||||
*
|
||||
* If the user specifies --empower but not --user= then consider this a request to empower
|
||||
* the current user. */
|
||||
|
||||
arg_exec_user = getusername_malloc();
|
||||
if (!arg_exec_user)
|
||||
return log_oom();
|
||||
@ -1211,8 +1228,8 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
|
||||
if (arg_lightweight >= 0) {
|
||||
const char *class =
|
||||
arg_lightweight ? (arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early-light" : "user-light") : "background-light") :
|
||||
(arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early" : "user") : "background");
|
||||
arg_lightweight ? (arg_stdio == ARG_STDIO_PTY ? (become_root() ? "user-early-light" : "user-light") : "background-light") :
|
||||
(arg_stdio == ARG_STDIO_PTY ? (become_root() ? "user-early" : "user") : "background");
|
||||
|
||||
log_debug("Setting XDG_SESSION_CLASS to '%s'.", class);
|
||||
|
||||
@ -1371,6 +1388,12 @@ static int transient_service_set_properties(sd_bus_message *m, const char *pty_p
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
if (arg_empower) {
|
||||
r = sd_bus_message_append(m, "(sv)", "AmbientCapabilities", "t", CAP_MASK_ALL);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
if (arg_nice_set) {
|
||||
r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice);
|
||||
if (r < 0)
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include "iovec-util.h"
|
||||
#include "libarchive-util.h"
|
||||
#include "path-util.h"
|
||||
#include "recurse-dir.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
@ -674,6 +675,145 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int archive_item(
|
||||
RecurseDirEvent event,
|
||||
const char *path,
|
||||
int dir_fd,
|
||||
int inode_fd,
|
||||
const struct dirent *de,
|
||||
const struct statx *sx,
|
||||
void *userdata) {
|
||||
|
||||
struct archive *a = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
if (!IN_SET(event, RECURSE_DIR_ENTER, RECURSE_DIR_ENTRY))
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
|
||||
assert(inode_fd >= 0);
|
||||
assert(sx);
|
||||
|
||||
log_debug("Archiving %s\n", path);
|
||||
|
||||
_cleanup_(archive_entry_freep) struct archive_entry *entry = NULL;
|
||||
entry = sym_archive_entry_new();
|
||||
if (!entry)
|
||||
return log_oom();
|
||||
|
||||
assert(FLAGS_SET(sx->stx_mask, STATX_TYPE|STATX_MODE));
|
||||
sym_archive_entry_set_pathname(entry, path);
|
||||
sym_archive_entry_set_filetype(entry, sx->stx_mode);
|
||||
|
||||
if (!S_ISLNK(sx->stx_mode))
|
||||
sym_archive_entry_set_perm(entry, sx->stx_mode);
|
||||
|
||||
if (FLAGS_SET(sx->stx_mask, STATX_UID))
|
||||
sym_archive_entry_set_uid(entry, sx->stx_uid);
|
||||
if (FLAGS_SET(sx->stx_mask, STATX_GID))
|
||||
sym_archive_entry_set_gid(entry, sx->stx_gid);
|
||||
|
||||
if (S_ISREG(sx->stx_mode)) {
|
||||
if (!FLAGS_SET(sx->stx_mask, STATX_SIZE))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Unable to determine file size of '%s'.", path);
|
||||
|
||||
sym_archive_entry_set_size(entry, sx->stx_size);
|
||||
}
|
||||
|
||||
if (S_ISCHR(sx->stx_mode) || S_ISBLK(sx->stx_mode)) {
|
||||
sym_archive_entry_set_rdevmajor(entry, sx->stx_rdev_major);
|
||||
sym_archive_entry_set_rdevminor(entry, sx->stx_rdev_minor);
|
||||
}
|
||||
|
||||
/* We care about a modicum of reproducibility here, hence we don't save atime/btime here */
|
||||
if (FLAGS_SET(sx->stx_mask, STATX_MTIME))
|
||||
sym_archive_entry_set_mtime(entry, sx->stx_mtime.tv_sec, sx->stx_mtime.tv_nsec);
|
||||
if (FLAGS_SET(sx->stx_mask, STATX_CTIME))
|
||||
sym_archive_entry_set_ctime(entry, sx->stx_ctime.tv_sec, sx->stx_ctime.tv_nsec);
|
||||
|
||||
if (S_ISLNK(sx->stx_mode)) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
assert(dir_fd >= 0);
|
||||
assert(de);
|
||||
|
||||
r = readlinkat_malloc(dir_fd, de->d_name, &s);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read symlink target of '%s': %m", path);
|
||||
|
||||
sym_archive_entry_set_symlink(entry, s);
|
||||
}
|
||||
|
||||
if (sym_archive_write_header(a, entry) != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to write archive entry header: %s", sym_archive_error_string(a));
|
||||
|
||||
if (S_ISREG(sx->stx_mode)) {
|
||||
_cleanup_close_ int data_fd = -EBADF;
|
||||
|
||||
/* Convert the O_PATH fd in a proper fd */
|
||||
data_fd = fd_reopen(inode_fd, O_RDONLY|O_CLOEXEC);
|
||||
if (data_fd < 0)
|
||||
return log_error_errno(data_fd, "Failed to open '%s': %m", path);
|
||||
|
||||
for (;;) {
|
||||
char buffer[64*1024];
|
||||
ssize_t l;
|
||||
|
||||
l = read(data_fd, buffer, sizeof(buffer));
|
||||
if (l < 0)
|
||||
return log_error_errno(errno, "Failed to read '%s': %m", path);
|
||||
if (l == 0)
|
||||
break;
|
||||
|
||||
la_ssize_t k;
|
||||
k = sym_archive_write_data(a, buffer, l);
|
||||
if (k < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to write archive data: %s", sym_archive_error_string(a));
|
||||
}
|
||||
}
|
||||
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
}
|
||||
|
||||
int tar_c(int tree_fd, int output_fd, const char *filename, TarFlags flags) {
|
||||
int r;
|
||||
|
||||
assert(tree_fd >= 0);
|
||||
assert(output_fd >= 0);
|
||||
|
||||
_cleanup_(archive_write_freep) struct archive *a = sym_archive_write_new();
|
||||
if (!a)
|
||||
return log_oom();
|
||||
|
||||
if (filename)
|
||||
r = sym_archive_write_set_format_filter_by_ext(a, filename);
|
||||
else
|
||||
r = sym_archive_write_set_format_gnutar(a);
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to set libarchive output format: %s", sym_archive_error_string(a));
|
||||
|
||||
r = sym_archive_write_open_fd(a, output_fd);
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to set libarchive output file: %s", sym_archive_error_string(a));
|
||||
|
||||
r = recurse_dir(tree_fd,
|
||||
".",
|
||||
STATX_TYPE|STATX_MODE|STATX_UID|STATX_GID|STATX_SIZE|STATX_ATIME|STATX_CTIME,
|
||||
UINT_MAX,
|
||||
RECURSE_DIR_SORT|RECURSE_DIR_INODE_FD|RECURSE_DIR_TOPLEVEL,
|
||||
archive_item,
|
||||
a);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make archive: %m");
|
||||
|
||||
r = sym_archive_write_close(a);
|
||||
if (r != ARCHIVE_OK)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to finish writing archive: %s", sym_archive_error_string(a));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
@ -683,4 +823,11 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libarchive support not available.");
|
||||
}
|
||||
|
||||
int tar_c(int tree_fd, int output_fd, const char *filename, TarFlags flags) {
|
||||
assert(tree_fd >= 0);
|
||||
assert(output_fd >= 0);
|
||||
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libarchive support not available.");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -6,3 +6,4 @@ typedef enum TarFlags {
|
||||
} TarFlags;
|
||||
|
||||
int tar_x(int input_fd, int tree_fd, TarFlags flags);
|
||||
int tar_c(int tree_fd, int output_fd, const char *filename, TarFlags flags);
|
||||
|
||||
@ -297,6 +297,14 @@ if [[ -e /usr/lib/pam.d/systemd-run0 ]] || [[ -e /etc/pam.d/systemd-run0 ]]; the
|
||||
# Validate when we invoke run0 without a tty, that depending on --pty it either allocates a tty or not
|
||||
assert_neq "$(run0 --pty tty < /dev/null)" "not a tty"
|
||||
assert_eq "$(run0 --pipe tty < /dev/null)" "not a tty"
|
||||
|
||||
# Validate that --empower gives all capabilities to a non-root user.
|
||||
caps="$(run0 -u testuser --empower systemd-analyze capability --mask "$(grep CapEff /proc/self/status | cut -d':' -f2)" --json=pretty | jq -r length)"
|
||||
assert_neq "$caps" "0"
|
||||
|
||||
run0 -u testuser --empower touch /run/empower
|
||||
assert_eq "$(stat -c "%U" /run/empower)" testuser
|
||||
rm /run/empower
|
||||
fi
|
||||
|
||||
# Tests whether intermediate disconnects corrupt us (modified testcase from https://github.com/systemd/systemd/issues/27204)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user