Merge pull request #2555 from poettering/coredump-fixes

Coredump fixes and more
This commit is contained in:
Lennart Poettering 2016-02-10 16:50:21 +01:00
commit 059adb5ac0
28 changed files with 940 additions and 503 deletions

View file

@ -4397,30 +4397,39 @@ systemd_socket_proxyd_LDADD = \
# ------------------------------------------------------------------------------
if ENABLE_COREDUMP
systemd_coredump_SOURCES = \
src/journal/coredump.c \
src/journal/coredump-vacuum.c \
src/journal/coredump-vacuum.h
src/coredump/coredump.c \
src/coredump/coredump-vacuum.c \
src/coredump/coredump-vacuum.h
systemd_coredump_LDADD = \
libshared.la
if HAVE_ELFUTILS
systemd_coredump_SOURCES += \
src/journal/stacktrace.c \
src/journal/stacktrace.h
src/coredump/stacktrace.c \
src/coredump/stacktrace.h
systemd_coredump_LDADD += \
$(ELFUTILS_LIBS)
endif
nodist_systemunit_DATA += \
units/systemd-coredump@.service
dist_systemunit_DATA += \
units/systemd-coredump.socket
SOCKETS_TARGET_WANTS += \
systemd-coredump.socket
rootlibexec_PROGRAMS += \
systemd-coredump
dist_pkgsysconf_DATA += \
src/journal/coredump.conf
src/coredump/coredump.conf
coredumpctl_SOURCES = \
src/journal/coredumpctl.c
src/coredump/coredumpctl.c
coredumpctl_LDADD = \
libshared.la
@ -4432,9 +4441,9 @@ manual_tests += \
test-coredump-vacuum
test_coredump_vacuum_SOURCES = \
src/journal/test-coredump-vacuum.c \
src/journal/coredump-vacuum.c \
src/journal/coredump-vacuum.h
src/coredump/test-coredump-vacuum.c \
src/coredump/coredump-vacuum.c \
src/coredump/coredump-vacuum.h
test_coredump_vacuum_LDADD = \
libshared.la
@ -4453,7 +4462,8 @@ CLEANFILES += \
endif
EXTRA_DIST += \
sysctl.d/50-coredump.conf.in
sysctl.d/50-coredump.conf.in \
units/systemd-coredump@.service.in
# ------------------------------------------------------------------------------
if ENABLE_BINFMT
@ -4860,7 +4870,6 @@ nodist_systemunit_DATA += \
GENERAL_ALIASES += \
$(systemunitdir)/systemd-timesyncd.service $(pkgsysconfdir)/system/sysinit.target.wants/systemd-timesyncd.service
nodist_pkgsysconf_DATA += \
src/timesync/timesyncd.conf

33
NEWS
View file

@ -26,6 +26,39 @@ CHANGES WITH 229:
* /dev/disk/by-path/ symlink support has been (re-)added for virtio
devices.
* The coredump collection logic has been reworked: when a coredump is
collected it is now written to disk, compressed and processed
(including stacktrace extraction) from a new instantiated service
systemd-coredump@.service, instead of directly from the
/proc/sys/kernel/core_pattern hook we provide. This is beneficial as
processing large coredumps can take up a substantial amount of
resources and time, and this previously happened entirely outside of
systemd's service supervision. With the new logic the core_pattern
hook only does minimal metadata collection before passing off control
to the new instantiated service, which is configured with a time
limit, a nice level and other settings to minimize negative impact on
the rest of the system. Also note that the new logic will honour the
RLIMIT_CORE setting of the crashed process, which now allows users
and processes to turn off coredumping for their processes by setting
this limit.
* The RLIMIT_CORE resource limit now defaults to "unlimited" for PID 1
and all forked processes by default. Previously, PID 1 would leave
the setting at "0" for all processes, as set by the kernel. Note that
the resource limit traditionally has no effect on the generated
coredumps on the system if the /proc/sys/kernel/core_pattern hook
logic is used. Since the limit is now honoured (see above) its
default has been changed so that the coredumping logic is enabled by
default for all processes, while allowing specific opt-out.
* When the stacktrace is extracted from processes of system users, this
is now done as "systemd-coredump" user, in order to sandbox this
potentially security sensitive parsing operation. (Note that when
processing coredumps of normal users this is done under the user ID
of process that crashed, as before.) Packagers should take notice
that it is now necessary to create the "systemd-coredump" system user
and group at package installation time.
* The systemd-activate socket activation testing tool gained support
for SOCK_DGRAM and SOCK_SEQPACKET sockets using the new --datagram
and --seqpacket switches. It also has been extended to support both

3
README
View file

@ -203,6 +203,9 @@ USERS AND GROUPS:
Similarly, the kdbus dbus1 proxy daemon requires the
"systemd-bus-proxy" system user and group to exist.
Similarly, the coredump support requires the
"systemd-coredump" system user and group to exist.
NSS:
systemd ships with three NSS modules:

11
TODO
View file

@ -33,8 +33,6 @@ Janitorial Clean-ups:
Features:
* rework coredump tool to move actual processing into a socket activated service
* cache sd_event_now() result from before the first iteration...
* remove Capabilities=, after all AmbientCapabilities= and CapabilityBoundingSet= should be enough.
@ -43,11 +41,6 @@ Features:
* add systemctl stop --job-mode=triggering that follows TRIGGERED_BY deps and adds them to the same transaction
* coredump logic should use prlimit() to query RLIMIT_CORE of the dumpee and honour it
* Add a MaxRuntimeSec= setting for service units (or units in general) to terminate units after they ran for a certain
amount of time
* Maybe add a way how users can "pin" units into memory, so that they are not subject to automatic GC?
* PID1: find a way how we can reload unit file configuration for
@ -649,10 +642,6 @@ Features:
* coredump:
- save coredump in Windows/Mozilla minidump format
- move PID 1 segfaults to /var/lib/systemd/coredump?
- make the handler check /proc/$PID/rlimits for RLIMIT_CORE,
and supress coredump if turned off. Then change RLIMIT_CORE to
infinity by default for all services. This then allows per-service
control of coredumping.
* support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting)

View file

@ -1106,6 +1106,7 @@ have_coredump=no
AC_ARG_ENABLE(coredump, AS_HELP_STRING([--disable-coredump], [disable coredump hook]))
if test "x$enable_coredump" != "xno"; then
have_coredump=yes
M4_DEFINES="$M4_DEFINES -DENABLE_COREDUMP"
fi
AM_CONDITIONAL(ENABLE_COREDUMP, [test "$have_coredump" = "yes"])

View file

@ -60,27 +60,21 @@
<refsect1>
<title>Description</title>
<para><command>systemd-activate</command> can be used to
launch a socket-activated daemon from the command line for
testing purposes. It can also be used to launch single instances
of the daemon per connection (inetd-style).
<para><command>systemd-activate</command> may be used to launch a socket-activated service binary from the command
line for testing purposes. It may also be used to launch individual instances of the service binary per connection.
</para>
<para>The daemon to launch and its options should be specified
after options intended for <command>systemd-activate</command>.
</para>
<para>If the <option>-a</option> option is given, file descriptor
of the connection will be used as the standard input and output of
the launched process. Otherwise, standard input and output will be
inherited, and sockets will be passed through file descriptors 3
and higher. Sockets passed through <varname>$LISTEN_FDS</varname>
to <command>systemd-activate</command> will be passed through to
the daemon, in the original positions. Other sockets specified
with <option>--listen</option> will use consecutive descriptors.
By default, <command>systemd-activate</command> listens on a
stream socket, use <option>--datagram</option> to listen on
a datagram socket instead (see below).
<para>If the <option>--inetd</option> option is given, the socket file descriptor will be used as the standard
input and output of the launched process. Otherwise, standard input and output will be inherited, and sockets will
be passed through file descriptors 3 and higher. Sockets passed through <varname>$LISTEN_FDS</varname> to
<command>systemd-activate</command> will be passed through to the daemon, in the original positions. Other sockets
specified with <option>--listen=</option> will use consecutive descriptors. By default,
<command>systemd-activate</command> listens on a stream socket, use <option>--datagram</option> and
<option>--seqpacket</option> to listen on datagram or sequential packet sockets instead (see below).
</para>
</refsect1>
@ -101,16 +95,32 @@
<term><option>-a</option></term>
<term><option>--accept</option></term>
<listitem><para>Launch a separate instance of daemon per
connection and pass the connection socket as standard input
and standard output.</para></listitem>
<listitem><para>Launch an instance of the service binary for each connection and pass the connection
socket.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-d</option></term>
<term><option>--datagram</option></term>
<listitem><para>Listen on a datagram socket, instead of a stream socket.</para></listitem>
<listitem><para>Listen on a datagram socket (<constant>SOCK_DGRAM</constant>), instead of a stream socket
(<constant>SOCK_STREAM</constant>). May not be combined with <option>--seqpacket</option>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--seqpacket</option></term>
<listitem><para>Listen on a sequential packet socket (<constant>SOCK_SEQPACKET</constant>), instead of a stream
socket (<constant>SOCK_STREAM</constant>). May not be combined with
<option>--datagram</option>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--inetd</option></term>
<listitem><para>Use the inetd protocol for passing file descriptors, i.e. as standard input and standard
output, instead of the new-style protocol for passing file descriptors using <varname>$LISTEN_FDS</varname>
(see above).</para></listitem>
</varlistentry>
<varlistentry>
@ -170,7 +180,7 @@
<example>
<title>Run an echo server on port 2000</title>
<programlisting>$ /usr/lib/systemd/systemd-activate -l 2000 -a cat</programlisting>
<programlisting>$ /usr/lib/systemd/systemd-activate -l 2000 --inetd -a cat</programlisting>
</example>
<example>

View file

@ -728,20 +728,14 @@
<term><varname>JobTimeoutAction=</varname></term>
<term><varname>JobTimeoutRebootArgument=</varname></term>
<listitem><para>When a job for this unit is queued, a time-out
may be configured. If this time limit is reached, the job will
be cancelled, the unit however will not change state or even
enter the <literal>failed</literal> mode. This value defaults
to 0 (job timeouts disabled), except for device units. NB:
this timeout is independent from any unit-specific timeout
(for example, the timeout set with
<varname>TimeoutStartSec=</varname> in service units) as the
job timeout has no effect on the unit itself, only on the job
that might be pending for it. Or in other words: unit-specific
timeouts are useful to abort unit state changes, and revert
them. The job timeout set with this option however is useful
to abort only the job waiting for the unit state to
change.</para>
<listitem><para>When a job for this unit is queued, a time-out may be configured. If this time limit is
reached, the job will be cancelled, the unit however will not change state or even enter the
<literal>failed</literal> mode. This value defaults to <literal>infinity</literal> (job timeouts disabled),
except for device units. NB: this timeout is independent from any unit-specific timeout (for example, the
timeout set with <varname>TimeoutStartSec=</varname> in service units) as the job timeout has no effect on the
unit itself, only on the job that might be pending for it. Or in other words: unit-specific timeouts are useful
to abort unit state changes, and revert them. The job timeout set with this option however is useful to abort
only the job waiting for the unit state to change.</para>
<para><varname>JobTimeoutAction=</varname>
optionally configures an additional

View file

@ -37,10 +37,11 @@
static char** arg_listen = NULL;
static bool arg_accept = false;
static bool arg_datagram = false;
static int arg_socket_type = SOCK_STREAM;
static char** arg_args = NULL;
static char** arg_setenv = NULL;
static const char *arg_fdname = NULL;
static bool arg_inetd = false;
static int add_epoll(int epoll_fd, int fd) {
struct epoll_event ev = {
@ -96,12 +97,7 @@ static int open_sockets(int *epoll_fd, bool accept) {
*/
STRV_FOREACH(address, arg_listen) {
if (arg_datagram)
fd = make_socket_fd(LOG_DEBUG, *address, SOCK_DGRAM, SOCK_CLOEXEC);
else
fd = make_socket_fd(LOG_DEBUG, *address, SOCK_STREAM, (arg_accept*SOCK_CLOEXEC));
fd = make_socket_fd(LOG_DEBUG, *address, arg_socket_type, (arg_accept*SOCK_CLOEXEC));
if (fd < 0) {
log_open();
return log_error_errno(fd, "Failed to open '%s': %m", *address);
@ -132,14 +128,20 @@ static int open_sockets(int *epoll_fd, bool accept) {
return count;
}
static int launch(char* name, char **argv, char **env, int fds) {
static int exec_process(const char* name, char **argv, char **env, int start_fd, int n_fds) {
static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="};
_cleanup_strv_free_ char **envp = NULL;
_cleanup_free_ char *tmp = NULL;
_cleanup_free_ char *joined = NULL;
unsigned n_env = 0, length;
char **s;
const char *tocopy;
unsigned i;
char **s;
int r;
if (arg_inetd && n_fds != 1) {
log_error("--inetd only supported for single file descriptors.");
return -EINVAL;
}
length = strv_length(arg_setenv);
@ -149,6 +151,7 @@ static int launch(char* name, char **argv, char **env, int fds) {
return log_oom();
STRV_FOREACH(s, arg_setenv) {
if (strchr(*s, '=')) {
char *k;
@ -172,13 +175,15 @@ static int launch(char* name, char **argv, char **env, int fds) {
envp[n_env] = strdup(n);
if (!envp[n_env])
return log_oom();
n_env ++;
}
}
for (i = 0; i < ELEMENTSOF(tocopy); i++) {
FOREACH_STRING(tocopy, "TERM=", "PATH=", "USER=", "HOME=") {
const char *n;
n = strv_find_prefix(env, tocopy[i]);
n = strv_find_prefix(env, tocopy);
if (!n)
continue;
@ -189,50 +194,76 @@ static int launch(char* name, char **argv, char **env, int fds) {
n_env ++;
}
if ((asprintf((char**)(envp + n_env++), "LISTEN_FDS=%d", fds) < 0) ||
(asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0))
return log_oom();
if (arg_inetd) {
assert(n_fds == 1);
if (arg_fdname) {
char *e;
r = dup2(start_fd, STDIN_FILENO);
if (r < 0)
return log_error_errno(errno, "Failed to dup connection to stdin: %m");
e = strappend("LISTEN_FDNAMES=", arg_fdname);
if (!e)
return log_oom();
r = dup2(start_fd, STDOUT_FILENO);
if (r < 0)
return log_error_errno(errno, "Failed to dup connection to stdout: %m");
for (i = 1; i < (unsigned) fds; i++) {
char *c;
start_fd = safe_close(start_fd);
} else {
if (start_fd != SD_LISTEN_FDS_START) {
assert(n_fds == 1);
c = strjoin(e, ":", arg_fdname, NULL);
if (!c) {
free(e);
return log_oom();
}
r = dup2(start_fd, SD_LISTEN_FDS_START);
if (r < 0)
return log_error_errno(errno, "Failed to dup connection: %m");
free(e);
e = c;
safe_close(start_fd);
start_fd = SD_LISTEN_FDS_START;
}
envp[n_env++] = e;
if (asprintf((char**)(envp + n_env++), "LISTEN_FDS=%i", n_fds) < 0)
return log_oom();
if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid()) < 0)
return log_oom();
if (arg_fdname) {
char *e;
e = strappend("LISTEN_FDNAMES=", arg_fdname);
if (!e)
return log_oom();
for (i = 1; i < (unsigned) n_fds; i++) {
char *c;
c = strjoin(e, ":", arg_fdname, NULL);
if (!c) {
free(e);
return log_oom();
}
free(e);
e = c;
}
envp[n_env++] = e;
}
}
tmp = strv_join(argv, " ");
if (!tmp)
joined = strv_join(argv, " ");
if (!joined)
return log_oom();
log_info("Execing %s (%s)", name, tmp);
log_info("Execing %s (%s)", name, joined);
execvpe(name, argv, envp);
return log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp);
return log_error_errno(errno, "Failed to execp %s (%s): %m", name, joined);
}
static int launch1(const char* child, char** argv, char **env, int fd) {
_cleanup_free_ char *tmp = NULL;
static int fork_and_exec_process(const char* child, char** argv, char **env, int fd) {
_cleanup_free_ char *joined = NULL;
pid_t parent_pid, child_pid;
int r;
tmp = strv_join(argv, " ");
if (!tmp)
joined = strv_join(argv, " ");
if (!joined)
return log_oom();
parent_pid = getpid();
@ -247,24 +278,6 @@ static int launch1(const char* child, char** argv, char **env, int fd) {
(void) reset_all_signal_handlers();
(void) reset_signal_mask();
r = dup2(fd, STDIN_FILENO);
if (r < 0) {
log_error_errno(errno, "Failed to dup connection to stdin: %m");
_exit(EXIT_FAILURE);
}
r = dup2(fd, STDOUT_FILENO);
if (r < 0) {
log_error_errno(errno, "Failed to dup connection to stdout: %m");
_exit(EXIT_FAILURE);
}
r = close(fd);
if (r < 0) {
log_error_errno(errno, "Failed to close dupped connection: %m");
_exit(EXIT_FAILURE);
}
/* Make sure the child goes away when the parent dies */
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
_exit(EXIT_FAILURE);
@ -274,31 +287,27 @@ static int launch1(const char* child, char** argv, char **env, int fd) {
if (getppid() != parent_pid)
_exit(EXIT_SUCCESS);
execvp(child, argv);
log_error_errno(errno, "Failed to exec child %s: %m", child);
exec_process(child, argv, env, fd, 1);
_exit(EXIT_FAILURE);
}
log_info("Spawned %s (%s) as PID %d", child, tmp, child_pid);
log_info("Spawned %s (%s) as PID %d", child, joined, child_pid);
return 0;
}
static int do_accept(const char* name, char **argv, char **envp, int fd) {
_cleanup_free_ char *local = NULL, *peer = NULL;
_cleanup_close_ int fd2 = -1;
_cleanup_close_ int fd_accepted = -1;
fd2 = accept(fd, NULL, NULL);
if (fd2 < 0) {
log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
return fd2;
}
fd_accepted = accept4(fd, NULL, NULL, 0);
if (fd_accepted < 0)
return log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
getsockname_pretty(fd2, &local);
getpeername_pretty(fd2, true, &peer);
getsockname_pretty(fd_accepted, &local);
getpeername_pretty(fd_accepted, true, &peer);
log_info("Connection from %s to %s", strna(peer), strna(local));
return launch1(name, argv, envp, fd2);
return fork_and_exec_process(name, argv, envp, fd_accepted);
}
/* SIGCHLD handler. */
@ -306,21 +315,24 @@ static void sigchld_hdl(int sig, siginfo_t *t, void *data) {
PROTECT_ERRNO;
log_info("Child %d died with code %d", t->si_pid, t->si_status);
/* Wait for a dead child. */
waitpid(t->si_pid, NULL, 0);
(void) waitpid(t->si_pid, NULL, 0);
}
static int install_chld_handler(void) {
int r;
struct sigaction act = {
static const struct sigaction act = {
.sa_flags = SA_SIGINFO,
.sa_sigaction = sigchld_hdl,
};
int r;
r = sigaction(SIGCHLD, &act, 0);
if (r < 0)
log_error_errno(errno, "Failed to install SIGCHLD handler: %m");
return r;
return log_error_errno(errno, "Failed to install SIGCHLD handler: %m");
return 0;
}
static void help(void) {
@ -331,8 +343,10 @@ static void help(void) {
" --version Print version string and exit\n"
" -l --listen=ADDR Listen for raw connections at ADDR\n"
" -d --datagram Listen on datagram instead of stream socket\n"
" --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n"
" -a --accept Spawn separate child for each connection\n"
" -E --setenv=NAME[=VALUE] Pass an environment variable to children\n"
" --inetd Enable inetd file descriptor passing protocol\n"
"\n"
"Note: file descriptors from sd_listen_fds() will be passed through.\n"
, program_invocation_short_name);
@ -342,17 +356,21 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_FDNAME,
ARG_SEQPACKET,
ARG_INETD,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "datagram", no_argument, NULL, 'd' },
{ "seqpacket", no_argument, NULL, ARG_SEQPACKET },
{ "listen", required_argument, NULL, 'l' },
{ "accept", no_argument, NULL, 'a' },
{ "setenv", required_argument, NULL, 'E' },
{ "environment", required_argument, NULL, 'E' }, /* legacy alias */
{ "fdname", required_argument, NULL, ARG_FDNAME },
{ "inetd", no_argument, NULL, ARG_INETD },
{}
};
@ -378,7 +396,21 @@ static int parse_argv(int argc, char *argv[]) {
break;
case 'd':
arg_datagram = true;
if (arg_socket_type == SOCK_SEQPACKET) {
log_error("--datagram may not be combined with --seqpacket.");
return -EINVAL;
}
arg_socket_type = SOCK_DGRAM;
break;
case ARG_SEQPACKET:
if (arg_socket_type == SOCK_DGRAM) {
log_error("--seqpacket may not be combined with --datagram.");
return -EINVAL;
}
arg_socket_type = SOCK_SEQPACKET;
break;
case 'a':
@ -401,6 +433,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_fdname = optarg;
break;
case ARG_INETD:
arg_inetd = true;
break;
case '?':
return -EINVAL;
@ -414,7 +450,7 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
if (arg_datagram && arg_accept) {
if (arg_socket_type == SOCK_DGRAM && arg_accept) {
log_error("Datagram sockets do not accept connections. "
"The --datagram and --accept options may not be combined.");
return -EINVAL;
@ -462,15 +498,14 @@ int main(int argc, char **argv, char **envp) {
log_info("Communication attempt on fd %i.", event.data.fd);
if (arg_accept) {
r = do_accept(argv[optind], argv + optind, envp,
event.data.fd);
r = do_accept(argv[optind], argv + optind, envp, event.data.fd);
if (r < 0)
return EXIT_FAILURE;
} else
break;
}
launch(argv[optind], argv + optind, envp, n);
exec_process(argv[optind], argv + optind, envp, SD_LISTEN_FDS_START, n);
return EXIT_SUCCESS;
}

View file

@ -871,14 +871,13 @@ int send_one_fd_sa(
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(int))];
} control = {};
struct cmsghdr *cmsg;
struct msghdr mh = {
.msg_name = (struct sockaddr*) sa,
.msg_namelen = len,
.msg_control = &control,
.msg_controllen = sizeof(control),
};
struct cmsghdr *cmsg;
assert(transport_fd >= 0);
assert(fd >= 0);

View file

@ -161,7 +161,7 @@ Unit.OnFailureJobMode, config_parse_job_mode, 0,
Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, offsetof(Unit, on_failure_job_mode)
Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate)
Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LEGACY, 0
Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout)
Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout)
Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action)
Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg)
Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
@ -215,9 +215,9 @@ Service.ExecReload, config_parse_exec, SERVICE_EXE
Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command)
Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command)
Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec)
Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
Service.TimeoutStartSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec)
Service.TimeoutSec, config_parse_service_timeout, 0, 0
Service.TimeoutStartSec, config_parse_service_timeout, 0, 0
Service.TimeoutStopSec, config_parse_service_timeout, 0, 0
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)

View file

@ -1711,18 +1711,20 @@ int config_parse_bus_name(
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
int config_parse_service_timeout(const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
int config_parse_service_timeout(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Service *s = userdata;
usec_t usec;
int r;
assert(filename);
@ -1730,25 +1732,63 @@ int config_parse_service_timeout(const char *unit,
assert(rvalue);
assert(s);
r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
rvalue, data, userdata);
if (r < 0)
return r;
/* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
if (streq(lvalue, "TimeoutSec")) {
s->start_timeout_defined = true;
s->timeout_stop_usec = s->timeout_start_usec;
} else if (streq(lvalue, "TimeoutStartSec"))
s->start_timeout_defined = true;
r = parse_sec(rvalue, &usec);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
return 0;
}
/* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
* immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
* all other timeouts. */
if (usec <= 0)
usec = USEC_INFINITY;
if (s->timeout_start_usec <= 0)
s->timeout_start_usec = USEC_INFINITY;
if (s->timeout_stop_usec <= 0)
s->timeout_stop_usec = USEC_INFINITY;
if (!streq(lvalue, "TimeoutStopSec")) {
s->start_timeout_defined = true;
s->timeout_start_usec = usec;
}
if (!streq(lvalue, "TimeoutStartSec"))
s->timeout_stop_usec = usec;
return 0;
}
int config_parse_sec_fix_0(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
usec_t *usec = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(usec);
/* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
* compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
* timeout. */
r = parse_sec(rvalue, usec);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
return 0;
}
if (*usec <= 0)
*usec = USEC_INFINITY;
return 0;
}

View file

@ -109,6 +109,7 @@ int config_parse_bus_name(const char* unit, const char *filename, unsigned line,
int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_fdname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_sec_fix_0(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);

View file

@ -172,19 +172,15 @@ noreturn static void crash(int sig) {
if (pid < 0)
log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
else if (pid == 0) {
struct rlimit rl = {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY,
};
/* Enable default signal handler for core dump */
sa = (struct sigaction) {
.sa_handler = SIG_DFL,
};
(void) sigaction(sig, &sa, NULL);
/* Don't limit the core dump size */
(void) setrlimit(RLIMIT_CORE, &rl);
/* Don't limit the coredump size */
(void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
/* Just to be sure... */
(void) chdir("/");
@ -1466,6 +1462,17 @@ int main(int argc, char *argv[]) {
kernel_timestamp = DUAL_TIMESTAMP_NULL;
}
if (getpid() == 1) {
/* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour the limit)
* will process core dumps for system services by default. */
(void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
/* But at the same time, turn off the core_pattern logic by default, so that no coredumps are stored
* until the systemd-coredump tool is enabled via sysctl. */
if (!skip_setup)
(void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0);
}
/* Initialize default unit */
r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET);
if (r < 0) {

1
src/coredump/Makefile Symbolic link
View file

@ -0,0 +1 @@
../Makefile

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
#define SD_RESOLVED_DNS (UINT64_C(1) << 0)
#define SD_RESOLVED_LLMNR_IPV4 (UINT64_C(1) << 1)
#define SD_RESOLVED_LLMNR_IPV6 (UINT64_C(1) << 2)

View file

@ -9,4 +9,4 @@
# and systemd-coredump(8) and core(5) for the explanation of the
# setting below.
kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %e
kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %e

View file

@ -16,3 +16,6 @@ u systemd-resolve - "systemd Resolver"
m4_ifdef(`ENABLE_TIMESYNCD',
u systemd-timesync - "systemd Time Synchronization"
)m4_dnl
m4_ifdef(`ENABLE_COREDUMP',
u systemd-coredump - "systemd Core Dumper"
)m4_dnl

1
units/.gitignore vendored
View file

@ -25,6 +25,7 @@
/systemd-binfmt.service
/systemd-bootchart.service
/systemd-bus-proxyd.service
/systemd-coredump@.service
/systemd-firstboot.service
/systemd-fsck-root.service
/systemd-fsck@.service

View file

@ -0,0 +1,17 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Process Core Dump Socket
Documentation=man:systemd-coredump(8)
DefaultDependencies=no
[Socket]
ListenSequentialPacket=/run/systemd/coredump
SocketMode=0600
Accept=yes
MaxConnections=16

View file

@ -0,0 +1,24 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Process Core Dump
Documentation=man:systemd-coredump(8)
DefaultDependencies=no
RequiresMountsFor=/var/lib/systemd/coredump
Conflicts=shutdown.target
After=systemd-remount-fs.service systemd-journald.socket
Requires=systemd-journald.socket
Before=shutdown.target
[Service]
ExecStart=-@rootlibexecdir@/systemd-coredump
Nice=9
OOMScoreAdjust=500
PrivateNetwork=yes
ProtectSystem=full
RuntimeMaxSec=5min