mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-10-28 03:25:27 +03:00
Merge pull request #3818 from poettering/exit-status-env
beef up /var/tmp and /tmp handling; set $SERVICE_RESULT/$EXIT_CODE/$EXIT_STATUS on ExecStop= and make sure root/nobody are always resolvable
This commit is contained in:
commit
3bb81a80bd
10
TODO
10
TODO
@ -35,27 +35,17 @@ Features:
|
||||
|
||||
* RemoveIPC= in unit files for removing POSIX/SysV IPC objects
|
||||
|
||||
* Set SERVICE_RESULT= as env var while running ExecStop=
|
||||
|
||||
* Introduce ProtectSystem=strict for making the entire OS hierarchy read-only
|
||||
except for a select few
|
||||
|
||||
* nspawn: start UID allocation loop from hash of container name
|
||||
|
||||
* in the DynamicUser=1 nss module, also map "nobody" and "root" statically
|
||||
|
||||
* pid1: log about all processes we kill with with SIGKILL or in abandoned scopes, as this should normally not happen
|
||||
|
||||
* nspawn: support that /proc, /sys/, /dev are pre-mounted
|
||||
|
||||
* nspawn: mount esp, so that bootctl can work
|
||||
|
||||
* define gpt header bits to select volatility mode
|
||||
|
||||
* nspawn: mount loopback filesystems with "discard"
|
||||
|
||||
* Make TasksMax= take percentages, taken relative to the pids_max sysctl and pids.max cgroup limit
|
||||
|
||||
* ProtectKernelLogs= (drops CAP_SYSLOG, add seccomp for syslog() syscall, and DeviceAllow to /dev/kmsg) in service files
|
||||
|
||||
* ProtectClock= (drops CAP_SYS_TIMES, adds seecomp filters for settimeofday, adjtimex), sets DeviceAllow o /dev/rtc
|
||||
|
22
configure.ac
22
configure.ac
@ -556,12 +556,30 @@ AC_SUBST(CERTIFICATEROOT)
|
||||
|
||||
AC_ARG_WITH([support-url],
|
||||
AS_HELP_STRING([--with-support-url=URL],
|
||||
[Specify the supoport URL to show in catalog entries included in systemd]),
|
||||
[Specify the support URL to show in catalog entries included in systemd]),
|
||||
[SUPPORT_URL="$withval"],
|
||||
[SUPPORT_URL=http://lists.freedesktop.org/mailman/listinfo/systemd-devel])
|
||||
|
||||
AC_SUBST(SUPPORT_URL)
|
||||
|
||||
AC_ARG_WITH([nobody-user],
|
||||
AS_HELP_STRING([--with-nobody-user=NAME],
|
||||
[Specify the name of the nobody user (the one with UID 65534)]),
|
||||
[NOBODY_USER_NAME="$withval"],
|
||||
[NOBODY_USER_NAME=nobody])
|
||||
|
||||
AC_SUBST(NOBODY_USER_NAME)
|
||||
AC_DEFINE_UNQUOTED(NOBODY_USER_NAME, ["$NOBODY_USER_NAME"], [The name of the nobody user (the one with UID 65534)])
|
||||
|
||||
AC_ARG_WITH([nobody-group],
|
||||
AS_HELP_STRING([--with-nobody-group=NAME],
|
||||
[Specify the name of the nobody group (the one with GID 65534)]),
|
||||
[NOBODY_GROUP_NAME="$withval"],
|
||||
[NOBODY_GROUP_NAME=nobody])
|
||||
|
||||
AC_SUBST(NOBODY_GROUP_NAME)
|
||||
AC_DEFINE_UNQUOTED(NOBODY_GROUP_NAME, ["$NOBODY_GROUP_NAME"], [The name of the nobody group (the one with GID 65534)])
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
have_xz=no
|
||||
AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support]))
|
||||
@ -1677,6 +1695,8 @@ AC_MSG_RESULT([
|
||||
Maximum System GID: ${SYSTEM_GID_MAX}
|
||||
Certificate root: ${CERTIFICATEROOT}
|
||||
Support URL: ${SUPPORT_URL}
|
||||
Nobody User Name: ${NOBODY_USER_NAME}
|
||||
Nobody Group Name: ${NOBODY_GROUP_NAME}
|
||||
|
||||
CFLAGS: ${OUR_CFLAGS} ${CFLAGS}
|
||||
CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
|
||||
|
@ -61,6 +61,10 @@
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details on
|
||||
this option.</para>
|
||||
|
||||
<para>This module also ensures that the root and nobody users and groups (i.e. the users/groups with the UIDs/GIDs
|
||||
0 and 65534) remain resolvable at all times, even if they aren't listed in <filename>/etc/passwd</filename> or
|
||||
<filename>/etc/group</filename>, or if these files are missing.</para>
|
||||
|
||||
<para>To activate the NSS module, add <literal>systemd</literal> to the lines starting with
|
||||
<literal>passwd:</literal> and <literal>group:</literal> in <filename>/etc/nsswitch.conf</filename>.</para>
|
||||
|
||||
|
@ -1602,6 +1602,43 @@
|
||||
functions) if their standard output or standard error output is connected to the journal anyway, thus enabling
|
||||
delivery of structured metadata along with logged messages.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>$SERVICE_RESULT</varname></term>
|
||||
|
||||
<listitem><para>Only defined for the service unit type, this environment variable is passed to all
|
||||
<varname>ExecStop=</varname> and <varname>ExecStopPost=</varname> processes, and encodes the service
|
||||
"result". Currently, the following values are defined: <literal>timeout</literal> (in case of an operation
|
||||
timeout), <literal>exit-code</literal> (if a service process exited with a non-zero exit code; see
|
||||
<varname>$EXIT_STATUS</varname> below for the actual exit status returned), <literal>signal</literal> (if a
|
||||
service process was terminated abnormally by a signal; see <varname>$EXIT_STATUS</varname> below for the actual
|
||||
signal used for the termination), <literal>core-dump</literal> (if a service process terminated abnormally and
|
||||
dumped core), <literal>watchdog</literal> (if the watchdog keep-alive ping was enabled for the service but it
|
||||
missed the deadline), or <literal>resources</literal> (a catch-all condition in case a system operation
|
||||
failed).</para>
|
||||
|
||||
<para>This environment variable is useful to monitor failure or successful termination of a service. Even
|
||||
though this variable is available in both <varname>ExecStop=</varname> and <varname>ExecStopPost=</varname>, it
|
||||
is usually a better choice to place monitoring tools in the latter, as the former is only invoked for services
|
||||
that managed to start up correctly, and the latter covers both services that failed during their start-up and
|
||||
those which failed during their runtime.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>$EXIT_CODE</varname></term>
|
||||
<term><varname>$EXIT_STATUS</varname></term>
|
||||
|
||||
<listitem><para>Only defined for the service unit type, these environment variables are passed to all
|
||||
<varname>ExecStop=</varname>, <varname>ExecStopPost=</varname> processes and contain exit status/code
|
||||
information of the main process of the service. For the precise definition of the exit code and status, see
|
||||
<citerefentry><refentrytitle>wait</refentrytitle><manvolnum>2</manvolnum></citerefentry>. <varname>$EXIT_CODE</varname>
|
||||
is one of <literal>exited</literal>, <literal>killed</literal>,
|
||||
<literal>dumped</literal>. <varname>$EXIT_STATUS</varname> contains the numeric exit code formatted as string
|
||||
if <varname>$EXIT_CODE</varname> is <literal>exited</literal>, and the signal name in all other cases. Note
|
||||
that these environment variables are only set if the service manager succeeded to start and identify the main
|
||||
process of the service.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>Additional variables may be configured by the following
|
||||
|
@ -429,7 +429,13 @@
|
||||
service failed to start up correctly. Commands configured with this setting need to be able to operate even if
|
||||
the service failed starting up half-way and left incompletely initialized data around. As the service's
|
||||
processes have been terminated already when the commands specified with this setting are executed they should
|
||||
not attempt to communicate with them.</para></listitem>
|
||||
not attempt to communicate with them.</para>
|
||||
|
||||
<para>Note that all commands that are configured with this setting are invoked with the result code of the
|
||||
service, as well as the main process' exit code and status, set in the <varname>$SERVICE_RESULT</varname>,
|
||||
<varname>$EXIT_CODE</varname> and <varname>$EXIT_STATUS</varname> environment variables, see
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -1168,8 +1168,8 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
||||
char *t, *x;
|
||||
uint64_t u;
|
||||
unsigned i;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
/* Turns this:
|
||||
@ -1178,6 +1178,12 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
||||
* /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
|
||||
*/
|
||||
|
||||
if (!p) {
|
||||
r = tmp_dir(&p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!extra)
|
||||
extra = "";
|
||||
|
||||
@ -1264,10 +1270,13 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
|
||||
|
||||
int open_tmpfile_unlinkable(const char *directory, int flags) {
|
||||
char *p;
|
||||
int fd;
|
||||
int fd, r;
|
||||
|
||||
if (!directory)
|
||||
directory = "/tmp";
|
||||
if (!directory) {
|
||||
r = tmp_dir(&directory);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Returns an unlinked temporary file that cannot be linked into the file system anymore */
|
||||
|
||||
|
@ -496,34 +496,94 @@ int get_files_in_directory(const char *path, char ***list) {
|
||||
return n;
|
||||
}
|
||||
|
||||
int var_tmp(char **ret) {
|
||||
const char *tmp_dir = NULL;
|
||||
const char *env_tmp_dir = NULL;
|
||||
char *c = NULL;
|
||||
int r;
|
||||
static int getenv_tmp_dir(const char **ret_path) {
|
||||
const char *n;
|
||||
int r, ret = 0;
|
||||
|
||||
assert(ret);
|
||||
assert(ret_path);
|
||||
|
||||
env_tmp_dir = getenv("TMPDIR");
|
||||
if (env_tmp_dir != NULL) {
|
||||
r = is_dir(env_tmp_dir, true);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r > 0)
|
||||
tmp_dir = env_tmp_dir;
|
||||
/* We use the same order of environment variables python uses in tempfile.gettempdir():
|
||||
* https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
|
||||
FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
|
||||
const char *e;
|
||||
|
||||
e = secure_getenv(n);
|
||||
if (!e)
|
||||
continue;
|
||||
if (!path_is_absolute(e)) {
|
||||
r = -ENOTDIR;
|
||||
goto next;
|
||||
}
|
||||
if (!path_is_safe(e)) {
|
||||
r = -EPERM;
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (!tmp_dir)
|
||||
tmp_dir = "/var/tmp";
|
||||
r = is_dir(e, true);
|
||||
if (r < 0)
|
||||
goto next;
|
||||
if (r == 0) {
|
||||
r = -ENOTDIR;
|
||||
goto next;
|
||||
}
|
||||
|
||||
c = strdup(tmp_dir);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
*ret = c;
|
||||
*ret_path = e;
|
||||
return 1;
|
||||
|
||||
next:
|
||||
/* Remember first error, to make this more debuggable */
|
||||
if (ret >= 0)
|
||||
ret = r;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*ret_path = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tmp_dir_internal(const char *def, const char **ret) {
|
||||
const char *e;
|
||||
int r, k;
|
||||
|
||||
assert(def);
|
||||
assert(ret);
|
||||
|
||||
r = getenv_tmp_dir(&e);
|
||||
if (r > 0) {
|
||||
*ret = e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
k = is_dir(def, true);
|
||||
if (k == 0)
|
||||
k = -ENOTDIR;
|
||||
if (k < 0)
|
||||
return r < 0 ? r : k;
|
||||
|
||||
*ret = def;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int var_tmp_dir(const char **ret) {
|
||||
|
||||
/* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
|
||||
* even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
|
||||
* returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
|
||||
* making it a variable that overrides all temporary file storage locations. */
|
||||
|
||||
return tmp_dir_internal("/var/tmp", ret);
|
||||
}
|
||||
|
||||
int tmp_dir(const char **ret) {
|
||||
|
||||
/* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
|
||||
* backed by an in-memory file system: /tmp. */
|
||||
|
||||
return tmp_dir_internal("/tmp", ret);
|
||||
}
|
||||
|
||||
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
|
||||
char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
||||
int r;
|
||||
|
@ -61,7 +61,8 @@ int mkfifo_atomic(const char *path, mode_t mode);
|
||||
|
||||
int get_files_in_directory(const char *path, char ***list);
|
||||
|
||||
int var_tmp(char **ret);
|
||||
int tmp_dir(const char **ret);
|
||||
int var_tmp_dir(const char **ret);
|
||||
|
||||
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
|
||||
|
||||
|
@ -301,7 +301,7 @@ static void automount_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
static void automount_enter_dead(Automount *a, AutomountResult f) {
|
||||
assert(a);
|
||||
|
||||
if (f != AUTOMOUNT_SUCCESS)
|
||||
if (a->result == AUTOMOUNT_SUCCESS)
|
||||
a->result = f;
|
||||
|
||||
automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
|
||||
|
@ -442,7 +442,7 @@ fail:
|
||||
static void busname_enter_dead(BusName *n, BusNameResult f) {
|
||||
assert(n);
|
||||
|
||||
if (f != BUSNAME_SUCCESS)
|
||||
if (n->result == BUSNAME_SUCCESS)
|
||||
n->result = f;
|
||||
|
||||
busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
|
||||
@ -454,7 +454,7 @@ static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f
|
||||
|
||||
assert(n);
|
||||
|
||||
if (f != BUSNAME_SUCCESS)
|
||||
if (n->result == BUSNAME_SUCCESS)
|
||||
n->result = f;
|
||||
|
||||
kill_context_init(&kill_context);
|
||||
@ -882,7 +882,7 @@ static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
log_unit_full(u, f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
|
||||
"Control process exited, code=%s status=%i", sigchld_code_to_string(code), status);
|
||||
|
||||
if (f != BUSNAME_SUCCESS)
|
||||
if (n->result == BUSNAME_SUCCESS)
|
||||
n->result = f;
|
||||
|
||||
switch (n->state) {
|
||||
|
@ -427,7 +427,7 @@ static int setup_input(
|
||||
return STDIN_FILENO;
|
||||
}
|
||||
|
||||
i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
|
||||
i = fixup_input(context->std_input, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
|
||||
|
||||
switch (i) {
|
||||
|
||||
@ -502,7 +502,7 @@ static int setup_output(
|
||||
return STDERR_FILENO;
|
||||
}
|
||||
|
||||
i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
|
||||
i = fixup_input(context->std_input, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
|
||||
o = fixup_output(context->std_output, socket_fd);
|
||||
|
||||
if (fileno == STDERR_FILENO) {
|
||||
@ -1425,7 +1425,7 @@ static int build_environment(
|
||||
our_env[n_env++] = x;
|
||||
}
|
||||
|
||||
if (p->watchdog_usec > 0) {
|
||||
if ((p->flags & EXEC_SET_WATCHDOG) && p->watchdog_usec > 0) {
|
||||
if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0)
|
||||
return -ENOMEM;
|
||||
our_env[n_env++] = x;
|
||||
@ -1675,7 +1675,7 @@ static int exec_child(
|
||||
|
||||
exec_context_tty_reset(context, params);
|
||||
|
||||
if (params->confirm_spawn) {
|
||||
if (params->flags & EXEC_CONFIRM_SPAWN) {
|
||||
char response;
|
||||
|
||||
r = ask_for_confirmation(&response, argv);
|
||||
@ -1940,7 +1940,7 @@ static int exec_child(
|
||||
|
||||
umask(context->umask);
|
||||
|
||||
if (params->apply_permissions && !command->privileged) {
|
||||
if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
|
||||
r = enforce_groups(context, username, gid);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_GROUP;
|
||||
@ -2010,7 +2010,7 @@ static int exec_child(
|
||||
}
|
||||
|
||||
r = setup_namespace(
|
||||
params->apply_chroot ? context->root_directory : NULL,
|
||||
(params->flags & EXEC_APPLY_CHROOT) ? context->root_directory : NULL,
|
||||
context->read_write_paths,
|
||||
context->read_only_paths,
|
||||
context->inaccessible_paths,
|
||||
@ -2041,7 +2041,7 @@ static int exec_child(
|
||||
else
|
||||
wd = "/";
|
||||
|
||||
if (params->apply_chroot) {
|
||||
if (params->flags & EXEC_APPLY_CHROOT) {
|
||||
if (!needs_mount_namespace && context->root_directory)
|
||||
if (chroot(context->root_directory) < 0) {
|
||||
*exit_status = EXIT_CHROOT;
|
||||
@ -2065,7 +2065,12 @@ static int exec_child(
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0 && !command->privileged) {
|
||||
if ((params->flags & EXEC_APPLY_PERMISSIONS) &&
|
||||
mac_selinux_use() &&
|
||||
params->selinux_context_net &&
|
||||
socket_fd >= 0 &&
|
||||
!command->privileged) {
|
||||
|
||||
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_SELINUX_CONTEXT;
|
||||
@ -2090,7 +2095,7 @@ static int exec_child(
|
||||
return r;
|
||||
}
|
||||
|
||||
if (params->apply_permissions && !command->privileged) {
|
||||
if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
|
||||
|
||||
bool use_address_families = context->address_families_whitelist ||
|
||||
!set_isempty(context->address_families);
|
||||
@ -2964,12 +2969,12 @@ void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
|
||||
"%sPID: "PID_FMT"\n",
|
||||
prefix, s->pid);
|
||||
|
||||
if (s->start_timestamp.realtime > 0)
|
||||
if (dual_timestamp_is_set(&s->start_timestamp))
|
||||
fprintf(f,
|
||||
"%sStart Timestamp: %s\n",
|
||||
prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
|
||||
|
||||
if (s->exit_timestamp.realtime > 0)
|
||||
if (dual_timestamp_is_set(&s->exit_timestamp))
|
||||
fprintf(f,
|
||||
"%sExit Timestamp: %s\n"
|
||||
"%sExit Code: %s\n"
|
||||
|
@ -208,6 +208,19 @@ struct ExecContext {
|
||||
bool no_new_privileges_set:1;
|
||||
};
|
||||
|
||||
typedef enum ExecFlags {
|
||||
EXEC_CONFIRM_SPAWN = 1U << 0,
|
||||
EXEC_APPLY_PERMISSIONS = 1U << 1,
|
||||
EXEC_APPLY_CHROOT = 1U << 2,
|
||||
EXEC_APPLY_TTY_STDIN = 1U << 3,
|
||||
|
||||
/* The following are not used by execute.c, but by consumers internally */
|
||||
EXEC_PASS_FDS = 1U << 4,
|
||||
EXEC_IS_CONTROL = 1U << 5,
|
||||
EXEC_SETENV_RESULT = 1U << 6,
|
||||
EXEC_SET_WATCHDOG = 1U << 7,
|
||||
} ExecFlags;
|
||||
|
||||
struct ExecParameters {
|
||||
char **argv;
|
||||
char **environment;
|
||||
@ -216,11 +229,7 @@ struct ExecParameters {
|
||||
char **fd_names;
|
||||
unsigned n_fds;
|
||||
|
||||
bool apply_permissions:1;
|
||||
bool apply_chroot:1;
|
||||
bool apply_tty_stdin:1;
|
||||
|
||||
bool confirm_spawn:1;
|
||||
ExecFlags flags;
|
||||
bool selinux_context_net:1;
|
||||
|
||||
bool cgroup_delegate:1;
|
||||
|
@ -701,9 +701,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
||||
pid_t pid;
|
||||
int r;
|
||||
ExecParameters exec_params = {
|
||||
.apply_permissions = true,
|
||||
.apply_chroot = true,
|
||||
.apply_tty_stdin = true,
|
||||
.flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
|
||||
.stdin_fd = -1,
|
||||
.stdout_fd = -1,
|
||||
.stderr_fd = -1,
|
||||
@ -732,7 +730,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
||||
return r;
|
||||
|
||||
exec_params.environment = UNIT(m)->manager->environment;
|
||||
exec_params.confirm_spawn = UNIT(m)->manager->confirm_spawn;
|
||||
exec_params.flags |= UNIT(m)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
|
||||
exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported;
|
||||
exec_params.cgroup_path = UNIT(m)->cgroup_path;
|
||||
exec_params.cgroup_delegate = m->cgroup_context.delegate;
|
||||
@ -761,7 +759,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
||||
static void mount_enter_dead(Mount *m, MountResult f) {
|
||||
assert(m);
|
||||
|
||||
if (f != MOUNT_SUCCESS)
|
||||
if (m->result == MOUNT_SUCCESS)
|
||||
m->result = f;
|
||||
|
||||
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
|
||||
@ -777,7 +775,7 @@ static void mount_enter_dead(Mount *m, MountResult f) {
|
||||
static void mount_enter_mounted(Mount *m, MountResult f) {
|
||||
assert(m);
|
||||
|
||||
if (f != MOUNT_SUCCESS)
|
||||
if (m->result == MOUNT_SUCCESS)
|
||||
m->result = f;
|
||||
|
||||
mount_set_state(m, MOUNT_MOUNTED);
|
||||
@ -788,7 +786,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
|
||||
|
||||
assert(m);
|
||||
|
||||
if (f != MOUNT_SUCCESS)
|
||||
if (m->result == MOUNT_SUCCESS)
|
||||
m->result = f;
|
||||
|
||||
r = unit_kill_context(
|
||||
@ -1160,7 +1158,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
else
|
||||
assert_not_reached("Unknown code");
|
||||
|
||||
if (f != MOUNT_SUCCESS)
|
||||
if (m->result == MOUNT_SUCCESS)
|
||||
m->result = f;
|
||||
|
||||
if (m->control_command) {
|
||||
|
@ -454,7 +454,7 @@ static int path_coldplug(Unit *u) {
|
||||
static void path_enter_dead(Path *p, PathResult f) {
|
||||
assert(p);
|
||||
|
||||
if (f != PATH_SUCCESS)
|
||||
if (p->result == PATH_SUCCESS)
|
||||
p->result = f;
|
||||
|
||||
path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
|
||||
|
@ -221,7 +221,7 @@ static void scope_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
static void scope_enter_dead(Scope *s, ScopeResult f) {
|
||||
assert(s);
|
||||
|
||||
if (f != SCOPE_SUCCESS)
|
||||
if (s->result == SCOPE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
|
||||
@ -233,7 +233,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
|
||||
|
||||
assert(s);
|
||||
|
||||
if (f != SCOPE_SUCCESS)
|
||||
if (s->result == SCOPE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
unit_watch_all_pids(UNIT(s));
|
||||
|
@ -1171,11 +1171,7 @@ static int service_spawn(
|
||||
Service *s,
|
||||
ExecCommand *c,
|
||||
usec_t timeout,
|
||||
bool pass_fds,
|
||||
bool apply_permissions,
|
||||
bool apply_chroot,
|
||||
bool apply_tty_stdin,
|
||||
bool is_control,
|
||||
ExecFlags flags,
|
||||
pid_t *_pid) {
|
||||
|
||||
_cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
|
||||
@ -1185,9 +1181,7 @@ static int service_spawn(
|
||||
pid_t pid;
|
||||
|
||||
ExecParameters exec_params = {
|
||||
.apply_permissions = apply_permissions,
|
||||
.apply_chroot = apply_chroot,
|
||||
.apply_tty_stdin = apply_tty_stdin,
|
||||
.flags = flags,
|
||||
.stdin_fd = -1,
|
||||
.stdout_fd = -1,
|
||||
.stderr_fd = -1,
|
||||
@ -1199,6 +1193,14 @@ static int service_spawn(
|
||||
assert(c);
|
||||
assert(_pid);
|
||||
|
||||
if (flags & EXEC_IS_CONTROL) {
|
||||
/* If this is a control process, mask the permissions/chroot application if this is requested. */
|
||||
if (s->permissions_start_only)
|
||||
exec_params.flags &= ~EXEC_APPLY_PERMISSIONS;
|
||||
if (s->root_directory_start_only)
|
||||
exec_params.flags &= ~EXEC_APPLY_CHROOT;
|
||||
}
|
||||
|
||||
(void) unit_realize_cgroup(UNIT(s));
|
||||
if (s->reset_cpu_usage) {
|
||||
(void) unit_reset_cpu_usage(UNIT(s));
|
||||
@ -1213,7 +1215,7 @@ static int service_spawn(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (pass_fds ||
|
||||
if ((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) {
|
||||
@ -1233,11 +1235,11 @@ static int service_spawn(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
our_env = new0(char*, 6);
|
||||
our_env = new0(char*, 9);
|
||||
if (!our_env)
|
||||
return -ENOMEM;
|
||||
|
||||
if (is_control ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
|
||||
if ((flags & EXEC_IS_CONTROL) ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
|
||||
if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1245,7 +1247,7 @@ static int service_spawn(
|
||||
if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
|
||||
if (MANAGER_IS_USER(UNIT(s)->manager))
|
||||
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1281,22 +1283,40 @@ static int service_spawn(
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & EXEC_SETENV_RESULT) {
|
||||
if (asprintf(our_env + n_env++, "SERVICE_RESULT=%s", service_result_to_string(s->result)) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (s->main_exec_status.pid > 0 &&
|
||||
dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) {
|
||||
if (asprintf(our_env + n_env++, "EXIT_CODE=%s", sigchld_code_to_string(s->main_exec_status.code)) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (s->main_exec_status.code == CLD_EXITED)
|
||||
r = asprintf(our_env + n_env++, "EXIT_STATUS=%i", s->main_exec_status.status);
|
||||
else
|
||||
r = asprintf(our_env + n_env++, "EXIT_STATUS=%s", signal_to_string(s->main_exec_status.status));
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
|
||||
if (!final_env)
|
||||
return -ENOMEM;
|
||||
|
||||
if (is_control && UNIT(s)->cgroup_path) {
|
||||
if ((flags & EXEC_IS_CONTROL) && UNIT(s)->cgroup_path) {
|
||||
path = strjoina(UNIT(s)->cgroup_path, "/control");
|
||||
(void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
|
||||
} else
|
||||
path = UNIT(s)->cgroup_path;
|
||||
|
||||
exec_params.argv = argv;
|
||||
exec_params.environment = final_env;
|
||||
exec_params.fds = fds;
|
||||
exec_params.fd_names = fd_names;
|
||||
exec_params.n_fds = n_fds;
|
||||
exec_params.environment = final_env;
|
||||
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
|
||||
exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
|
||||
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
||||
exec_params.cgroup_path = path;
|
||||
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
||||
@ -1422,7 +1442,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
int r;
|
||||
assert(s);
|
||||
|
||||
if (f != SERVICE_SUCCESS)
|
||||
if (s->result == SERVICE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
|
||||
@ -1471,7 +1491,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
|
||||
int r;
|
||||
assert(s);
|
||||
|
||||
if (f != SERVICE_SUCCESS)
|
||||
if (s->result == SERVICE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
service_unwatch_control_pid(s);
|
||||
@ -1484,11 +1504,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
s->timeout_stop_usec,
|
||||
false,
|
||||
!s->permissions_start_only,
|
||||
!s->root_directory_start_only,
|
||||
true,
|
||||
true,
|
||||
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
|
||||
&s->control_pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -1528,7 +1544,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
|
||||
|
||||
assert(s);
|
||||
|
||||
if (f != SERVICE_SUCCESS)
|
||||
if (s->result == SERVICE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
unit_watch_all_pids(UNIT(s));
|
||||
@ -1586,7 +1602,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
|
||||
|
||||
assert(s);
|
||||
|
||||
if (f != SERVICE_SUCCESS)
|
||||
if (s->result == SERVICE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
service_unwatch_control_pid(s);
|
||||
@ -1599,11 +1615,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
s->timeout_stop_usec,
|
||||
false,
|
||||
!s->permissions_start_only,
|
||||
!s->root_directory_start_only,
|
||||
false,
|
||||
true,
|
||||
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
|
||||
&s->control_pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -1642,7 +1654,7 @@ static bool service_good(Service *s) {
|
||||
static void service_enter_running(Service *s, ServiceResult f) {
|
||||
assert(s);
|
||||
|
||||
if (f != SERVICE_SUCCESS)
|
||||
if (s->result == SERVICE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
service_unwatch_control_pid(s);
|
||||
@ -1680,11 +1692,7 @@ static void service_enter_start_post(Service *s) {
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
s->timeout_start_usec,
|
||||
false,
|
||||
!s->permissions_start_only,
|
||||
!s->root_directory_start_only,
|
||||
false,
|
||||
true,
|
||||
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
|
||||
&s->control_pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -1754,11 +1762,7 @@ static void service_enter_start(Service *s) {
|
||||
r = service_spawn(s,
|
||||
c,
|
||||
timeout,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
EXEC_PASS_FDS|EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
|
||||
&pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -1817,11 +1821,7 @@ static void service_enter_start_pre(Service *s) {
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
s->timeout_start_usec,
|
||||
false,
|
||||
!s->permissions_start_only,
|
||||
!s->root_directory_start_only,
|
||||
true,
|
||||
true,
|
||||
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
|
||||
&s->control_pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -1896,11 +1896,7 @@ static void service_enter_reload(Service *s) {
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
s->timeout_start_usec,
|
||||
false,
|
||||
!s->permissions_start_only,
|
||||
!s->root_directory_start_only,
|
||||
false,
|
||||
true,
|
||||
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
|
||||
&s->control_pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -1938,12 +1934,9 @@ static void service_run_next_control(Service *s) {
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
timeout,
|
||||
false,
|
||||
!s->permissions_start_only,
|
||||
!s->root_directory_start_only,
|
||||
s->control_command_id == SERVICE_EXEC_START_PRE ||
|
||||
s->control_command_id == SERVICE_EXEC_STOP_POST,
|
||||
true,
|
||||
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|
|
||||
(IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_STOP_POST) ? EXEC_APPLY_TTY_STDIN : 0)|
|
||||
(IN_SET(s->control_command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST) ? EXEC_SETENV_RESULT : 0),
|
||||
&s->control_pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -1981,11 +1974,7 @@ static void service_run_next_main(Service *s) {
|
||||
r = service_spawn(s,
|
||||
s->main_command,
|
||||
s->timeout_start_usec,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
EXEC_PASS_FDS|EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
|
||||
&pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -2656,7 +2645,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
"EXIT_STATUS=%i", status,
|
||||
NULL);
|
||||
|
||||
if (f != SERVICE_SUCCESS)
|
||||
if (s->result == SERVICE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
if (s->main_command &&
|
||||
@ -2737,7 +2726,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
"Control process exited, code=%s status=%i",
|
||||
sigchld_code_to_string(code), status);
|
||||
|
||||
if (f != SERVICE_SUCCESS)
|
||||
if (s->result == SERVICE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
/* Immediately get rid of the cgroup, so that the
|
||||
|
@ -1749,9 +1749,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
|
||||
pid_t pid;
|
||||
int r;
|
||||
ExecParameters exec_params = {
|
||||
.apply_permissions = true,
|
||||
.apply_chroot = true,
|
||||
.apply_tty_stdin = true,
|
||||
.flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
|
||||
.stdin_fd = -1,
|
||||
.stdout_fd = -1,
|
||||
.stderr_fd = -1,
|
||||
@ -1785,7 +1783,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
|
||||
|
||||
exec_params.argv = argv;
|
||||
exec_params.environment = UNIT(s)->manager->environment;
|
||||
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
|
||||
exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
|
||||
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
||||
exec_params.cgroup_path = UNIT(s)->cgroup_path;
|
||||
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
||||
@ -1897,7 +1895,7 @@ fail:
|
||||
static void socket_enter_dead(Socket *s, SocketResult f) {
|
||||
assert(s);
|
||||
|
||||
if (f != SOCKET_SUCCESS)
|
||||
if (s->result == SOCKET_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
|
||||
@ -1916,7 +1914,7 @@ static void socket_enter_stop_post(Socket *s, SocketResult f) {
|
||||
int r;
|
||||
assert(s);
|
||||
|
||||
if (f != SOCKET_SUCCESS)
|
||||
if (s->result == SOCKET_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
socket_unwatch_control_pid(s);
|
||||
@ -1944,7 +1942,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
|
||||
|
||||
assert(s);
|
||||
|
||||
if (f != SOCKET_SUCCESS)
|
||||
if (s->result == SOCKET_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
r = unit_kill_context(
|
||||
@ -1988,7 +1986,7 @@ static void socket_enter_stop_pre(Socket *s, SocketResult f) {
|
||||
int r;
|
||||
assert(s);
|
||||
|
||||
if (f != SOCKET_SUCCESS)
|
||||
if (s->result == SOCKET_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
socket_unwatch_control_pid(s);
|
||||
@ -2770,7 +2768,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
"Control process exited, code=%s status=%i",
|
||||
sigchld_code_to_string(code), status);
|
||||
|
||||
if (f != SOCKET_SUCCESS)
|
||||
if (s->result == SOCKET_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
if (s->control_command &&
|
||||
|
@ -611,9 +611,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
|
||||
pid_t pid;
|
||||
int r;
|
||||
ExecParameters exec_params = {
|
||||
.apply_permissions = true,
|
||||
.apply_chroot = true,
|
||||
.apply_tty_stdin = true,
|
||||
.flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
|
||||
.stdin_fd = -1,
|
||||
.stdout_fd = -1,
|
||||
.stderr_fd = -1,
|
||||
@ -642,7 +640,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
|
||||
goto fail;
|
||||
|
||||
exec_params.environment = UNIT(s)->manager->environment;
|
||||
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
|
||||
exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
|
||||
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
||||
exec_params.cgroup_path = UNIT(s)->cgroup_path;
|
||||
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
||||
@ -675,7 +673,7 @@ fail:
|
||||
static void swap_enter_dead(Swap *s, SwapResult f) {
|
||||
assert(s);
|
||||
|
||||
if (f != SWAP_SUCCESS)
|
||||
if (s->result == SWAP_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
|
||||
@ -691,7 +689,7 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
|
||||
static void swap_enter_active(Swap *s, SwapResult f) {
|
||||
assert(s);
|
||||
|
||||
if (f != SWAP_SUCCESS)
|
||||
if (s->result == SWAP_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
swap_set_state(s, SWAP_ACTIVE);
|
||||
@ -702,7 +700,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
|
||||
|
||||
assert(s);
|
||||
|
||||
if (f != SWAP_SUCCESS)
|
||||
if (s->result == SWAP_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
r = unit_kill_context(
|
||||
@ -999,7 +997,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
else
|
||||
assert_not_reached("Unknown code");
|
||||
|
||||
if (f != SWAP_SUCCESS)
|
||||
if (s->result == SWAP_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
if (s->control_command) {
|
||||
|
@ -291,7 +291,7 @@ static int timer_coldplug(Unit *u) {
|
||||
static void timer_enter_dead(Timer *t, TimerResult f) {
|
||||
assert(t);
|
||||
|
||||
if (f != TIMER_SUCCESS)
|
||||
if (t->result == TIMER_SUCCESS)
|
||||
t->result = f;
|
||||
|
||||
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "compress.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "journal-internal.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
@ -609,7 +610,13 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
|
||||
char *temp = NULL;
|
||||
|
||||
if (fd < 0) {
|
||||
temp = strdup("/var/tmp/coredump-XXXXXX");
|
||||
const char *vt;
|
||||
|
||||
r = var_tmp_dir(&vt);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to acquire temporary directory path: %m");
|
||||
|
||||
temp = strjoin(vt, "/coredump-XXXXXX", NULL);
|
||||
if (!temp)
|
||||
return log_oom();
|
||||
|
||||
|
@ -826,7 +826,7 @@ int journal_file_verify(
|
||||
int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
|
||||
unsigned i;
|
||||
bool found_last = false;
|
||||
_cleanup_free_ char *tmp_dir = NULL;
|
||||
const char *tmp_dir = NULL;
|
||||
|
||||
#ifdef HAVE_GCRYPT
|
||||
uint64_t last_tag = 0;
|
||||
@ -846,7 +846,7 @@ int journal_file_verify(
|
||||
} else if (f->seal)
|
||||
return -ENOKEY;
|
||||
|
||||
r = var_tmp(&tmp_dir);
|
||||
r = var_tmp_dir(&tmp_dir);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to determine temporary directory: %m");
|
||||
goto fail;
|
||||
|
@ -954,7 +954,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
|
||||
/* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
|
||||
* instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
|
||||
* continuously */
|
||||
result_fd = open_tmpfile_unlinkable("/tmp/", O_RDWR|O_CLOEXEC);
|
||||
result_fd = open_tmpfile_unlinkable(NULL, O_RDWR|O_CLOEXEC);
|
||||
if (result_fd < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -26,9 +26,52 @@
|
||||
#include "macro.h"
|
||||
#include "nss-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "string-util.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifndef NOBODY_USER_NAME
|
||||
#define NOBODY_USER_NAME "nobody"
|
||||
#endif
|
||||
|
||||
#ifndef NOBODY_GROUP_NAME
|
||||
#define NOBODY_GROUP_NAME "nobody"
|
||||
#endif
|
||||
|
||||
static const struct passwd root_passwd = {
|
||||
.pw_name = (char*) "root",
|
||||
.pw_passwd = (char*) "x", /* see shadow file */
|
||||
.pw_uid = 0,
|
||||
.pw_gid = 0,
|
||||
.pw_gecos = (char*) "Super User",
|
||||
.pw_dir = (char*) "/root",
|
||||
.pw_shell = (char*) "/bin/sh",
|
||||
};
|
||||
|
||||
static const struct passwd nobody_passwd = {
|
||||
.pw_name = (char*) NOBODY_USER_NAME,
|
||||
.pw_passwd = (char*) "*", /* locked */
|
||||
.pw_uid = 65534,
|
||||
.pw_gid = 65534,
|
||||
.pw_gecos = (char*) "User Nobody",
|
||||
.pw_dir = (char*) "/",
|
||||
.pw_shell = (char*) "/sbin/nologin",
|
||||
};
|
||||
|
||||
static const struct group root_group = {
|
||||
.gr_name = (char*) "root",
|
||||
.gr_gid = 0,
|
||||
.gr_passwd = (char*) "x", /* see shadow file */
|
||||
.gr_mem = (char*[]) { NULL },
|
||||
};
|
||||
|
||||
static const struct group nobody_group = {
|
||||
.gr_name = (char*) NOBODY_GROUP_NAME,
|
||||
.gr_gid = 65534,
|
||||
.gr_passwd = (char*) "*", /* locked */
|
||||
.gr_mem = (char*[]) { NULL },
|
||||
};
|
||||
|
||||
NSS_GETPW_PROTOTYPES(systemd);
|
||||
NSS_GETGR_PROTOTYPES(systemd);
|
||||
|
||||
@ -50,6 +93,23 @@ enum nss_status _nss_systemd_getpwnam_r(
|
||||
assert(name);
|
||||
assert(pwd);
|
||||
|
||||
if (!valid_user_group_name(name)) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
|
||||
if (streq(name, root_passwd.pw_name)) {
|
||||
*pwd = root_passwd;
|
||||
*errnop = 0;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
if (streq(name, nobody_passwd.pw_name)) {
|
||||
*pwd = nobody_passwd;
|
||||
*errnop = 0;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
|
||||
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
|
||||
goto not_found;
|
||||
@ -126,6 +186,18 @@ enum nss_status _nss_systemd_getpwuid_r(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
|
||||
if (uid == root_passwd.pw_uid) {
|
||||
*pwd = root_passwd;
|
||||
*errnop = 0;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
if (uid == nobody_passwd.pw_uid) {
|
||||
*pwd = nobody_passwd;
|
||||
*errnop = 0;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (uid <= SYSTEM_UID_MAX)
|
||||
goto not_found;
|
||||
|
||||
@ -202,6 +274,23 @@ enum nss_status _nss_systemd_getgrnam_r(
|
||||
assert(name);
|
||||
assert(gr);
|
||||
|
||||
if (!valid_user_group_name(name)) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Synthesize records for root and nobody, in case they are missing form /etc/group */
|
||||
if (streq(name, root_group.gr_name)) {
|
||||
*gr = root_group;
|
||||
*errnop = 0;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
if (streq(name, nobody_group.gr_name)) {
|
||||
*gr = nobody_group;
|
||||
*errnop = 0;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
|
||||
goto not_found;
|
||||
|
||||
@ -275,6 +364,18 @@ enum nss_status _nss_systemd_getgrgid_r(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Synthesize records for root and nobody, in case they are missing from /etc/group */
|
||||
if (gid == root_group.gr_gid) {
|
||||
*gr = root_group;
|
||||
*errnop = 0;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
if (gid == nobody_group.gr_gid) {
|
||||
*gr = nobody_group;
|
||||
*errnop = 0;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (gid <= SYSTEM_GID_MAX)
|
||||
goto not_found;
|
||||
|
||||
|
@ -83,47 +83,35 @@ static void test_get_files_in_directory(void) {
|
||||
}
|
||||
|
||||
static void test_var_tmp(void) {
|
||||
char *tmp_dir = NULL;
|
||||
char *tmpdir_backup = NULL;
|
||||
const char *default_var_tmp = NULL;
|
||||
const char *var_name;
|
||||
bool do_overwrite = true;
|
||||
_cleanup_free_ char *tmpdir_backup = NULL;
|
||||
const char *tmp_dir = NULL, *t;
|
||||
|
||||
default_var_tmp = "/var/tmp";
|
||||
var_name = "TMPDIR";
|
||||
|
||||
if (getenv(var_name) != NULL) {
|
||||
tmpdir_backup = strdup(getenv(var_name));
|
||||
assert_se(tmpdir_backup != NULL);
|
||||
t = getenv("TMPDIR");
|
||||
if (t) {
|
||||
tmpdir_backup = strdup(t);
|
||||
assert_se(tmpdir_backup);
|
||||
}
|
||||
|
||||
unsetenv(var_name);
|
||||
assert(unsetenv("TMPDIR") >= 0);
|
||||
|
||||
var_tmp(&tmp_dir);
|
||||
assert_se(!strcmp(tmp_dir, default_var_tmp));
|
||||
assert_se(var_tmp_dir(&tmp_dir) >= 0);
|
||||
assert_se(streq(tmp_dir, "/var/tmp"));
|
||||
|
||||
free(tmp_dir);
|
||||
assert_se(setenv("TMPDIR", "/tmp", true) >= 0);
|
||||
assert_se(streq(getenv("TMPDIR"), "/tmp"));
|
||||
|
||||
setenv(var_name, "/tmp", do_overwrite);
|
||||
assert_se(!strcmp(getenv(var_name), "/tmp"));
|
||||
assert_se(var_tmp_dir(&tmp_dir) >= 0);
|
||||
assert_se(streq(tmp_dir, "/tmp"));
|
||||
|
||||
var_tmp(&tmp_dir);
|
||||
assert_se(!strcmp(tmp_dir, "/tmp"));
|
||||
assert_se(setenv("TMPDIR", "/88_does_not_exist_88", true) >= 0);
|
||||
assert_se(streq(getenv("TMPDIR"), "/88_does_not_exist_88"));
|
||||
|
||||
free(tmp_dir);
|
||||
assert_se(var_tmp_dir(&tmp_dir) >= 0);
|
||||
assert_se(streq(tmp_dir, "/var/tmp"));
|
||||
|
||||
setenv(var_name, "/88_does_not_exist_88", do_overwrite);
|
||||
assert_se(!strcmp(getenv(var_name), "/88_does_not_exist_88"));
|
||||
|
||||
var_tmp(&tmp_dir);
|
||||
assert_se(!strcmp(tmp_dir, default_var_tmp));
|
||||
|
||||
free(tmp_dir);
|
||||
|
||||
if (tmpdir_backup != NULL) {
|
||||
setenv(var_name, tmpdir_backup, do_overwrite);
|
||||
assert_se(!strcmp(getenv(var_name), tmpdir_backup));
|
||||
free(tmpdir_backup);
|
||||
if (tmpdir_backup) {
|
||||
assert_se(setenv("TMPDIR", tmpdir_backup, true) >= 0);
|
||||
assert_se(streq(getenv("TMPDIR"), tmpdir_backup));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user