1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <sys/reboot.h>
4
5 #include "crash-handler.h"
6 #include "exit-status.h"
7 #include "macro.h"
8 #include "main.h"
9 #include "missing_syscall.h"
10 #include "process-util.h"
11 #include "raw-clone.h"
12 #include "rlimit-util.h"
13 #include "signal-util.h"
14 #include "terminal-util.h"
15 #include "virt.h"
16
freeze_or_exit_or_reboot(void)17 _noreturn_ void freeze_or_exit_or_reboot(void) {
18
19 /* If we are running in a container, let's prefer exiting, after all we can propagate an exit code to
20 * the container manager, and thus inform it that something went wrong. */
21 if (detect_container() > 0) {
22 log_emergency("Exiting PID 1...");
23 _exit(EXIT_EXCEPTION);
24 }
25
26 if (arg_crash_reboot) {
27 log_notice("Rebooting in 10s...");
28 (void) sleep(10);
29
30 log_notice("Rebooting now...");
31 (void) reboot(RB_AUTOBOOT);
32 log_emergency_errno(errno, "Failed to reboot: %m");
33 }
34
35 log_emergency("Freezing execution.");
36 sync();
37 freeze();
38 }
39
crash(int sig,siginfo_t * siginfo,void * context)40 _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
41 struct sigaction sa;
42 pid_t pid;
43
44 /* NB: This is a signal handler, most likely executed in a situation where we have corrupted
45 * memory. Thus: please avoid any libc memory allocation here, or any functions that internally use
46 * memory allocation, as we cannot rely on memory allocation still working at this point! (Note that
47 * memory allocation is not async-signal-safe anyway — see signal-safety(7) for details —, and thus
48 * is not permissible in signal handlers.) */
49
50 if (getpid_cached() != 1)
51 /* Pass this on immediately, if this is not PID 1 */
52 (void) raise(sig);
53 else if (!arg_dump_core)
54 log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
55 else {
56 sa = (struct sigaction) {
57 .sa_handler = nop_signal_handler,
58 .sa_flags = SA_NOCLDSTOP|SA_RESTART,
59 };
60
61 /* We want to wait for the core process, hence let's enable SIGCHLD */
62 (void) sigaction(SIGCHLD, &sa, NULL);
63
64 pid = raw_clone(SIGCHLD);
65 if (pid < 0)
66 log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
67 else if (pid == 0) {
68 /* Enable default signal handler for core dump */
69
70 sa = (struct sigaction) {
71 .sa_handler = SIG_DFL,
72 };
73 (void) sigaction(sig, &sa, NULL);
74
75 /* Don't limit the coredump size */
76 (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
77
78 /* Just to be sure... */
79 (void) chdir("/");
80
81 /* Raise the signal again */
82 pid = raw_getpid();
83 (void) kill(pid, sig); /* raise() would kill the parent */
84
85 assert_not_reached();
86 _exit(EXIT_EXCEPTION);
87 } else {
88 siginfo_t status;
89 int r;
90
91 if (siginfo) {
92 if (siginfo->si_pid == 0)
93 log_emergency("Caught <%s> from unknown sender process.", signal_to_string(sig));
94 else if (siginfo->si_pid == 1)
95 log_emergency("Caught <%s> from our own process.", signal_to_string(sig));
96 else
97 log_emergency("Caught <%s> from PID "PID_FMT".", signal_to_string(sig), siginfo->si_pid);
98 }
99
100 /* Order things nicely. */
101 r = wait_for_terminate(pid, &status);
102 if (r < 0)
103 log_emergency_errno(r, "Caught <%s>, waitpid() failed: %m", signal_to_string(sig));
104 else if (status.si_code != CLD_DUMPED) {
105 const char *s = status.si_code == CLD_EXITED
106 ? exit_status_to_string(status.si_status, EXIT_STATUS_LIBC)
107 : signal_to_string(status.si_status);
108
109 log_emergency("Caught <%s>, core dump failed (child "PID_FMT", code=%s, status=%i/%s).",
110 signal_to_string(sig),
111 pid,
112 sigchld_code_to_string(status.si_code),
113 status.si_status, strna(s));
114 } else
115 log_emergency("Caught <%s>, dumped core as pid "PID_FMT".",
116 signal_to_string(sig), pid);
117 }
118 }
119
120 if (arg_crash_chvt >= 0)
121 (void) chvt(arg_crash_chvt);
122
123 sa = (struct sigaction) {
124 .sa_handler = SIG_IGN,
125 .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
126 };
127
128 /* Let the kernel reap children for us */
129 (void) sigaction(SIGCHLD, &sa, NULL);
130
131 if (arg_crash_shell) {
132 log_notice("Executing crash shell in 10s...");
133 (void) sleep(10);
134
135 pid = raw_clone(SIGCHLD);
136 if (pid < 0)
137 log_emergency_errno(errno, "Failed to fork off crash shell: %m");
138 else if (pid == 0) {
139 (void) setsid();
140 (void) make_console_stdio();
141 (void) rlimit_nofile_safe();
142 (void) execle("/bin/sh", "/bin/sh", NULL, environ);
143
144 log_emergency_errno(errno, "execle() failed: %m");
145 _exit(EXIT_EXCEPTION);
146 } else {
147 log_info("Spawned crash shell as PID "PID_FMT".", pid);
148 (void) wait_for_terminate(pid, NULL);
149 }
150 }
151
152 freeze_or_exit_or_reboot();
153 }
154
install_crash_handler(void)155 void install_crash_handler(void) {
156 static const struct sigaction sa = {
157 .sa_sigaction = crash,
158 .sa_flags = SA_NODEFER | SA_SIGINFO, /* So that we can raise the signal again from the signal handler */
159 };
160 int r;
161
162 /* We ignore the return value here, since, we don't mind if we cannot set up a crash handler */
163 r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER);
164 if (r < 0)
165 log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m");
166 }
167